Railway Operation Simulator  v2.4.2
A railway simulator for Windows
InterfaceUnit.cpp
Go to the documentation of this file.
1 // InterfaceUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <vcl.h>
39 #include <stdio.h>
40 #include <algorithm> //for sort
41 
42 #pragma hdrstop
43 // The above batch of include files above #pragma hdrstop appear in all .cpp files.
44 // They aren't all needed in each case but being together and identical they speed
45 // up compilation considerably (without ~14 min, with ~1 min!). They are used in
46 // conjunction with 'use pre-compiled headers' in the project compiler options.
47 
48 #include "InterfaceUnit.h"
49 #include "GraphicUnit.h"
50 #include "DisplayUnit.h"
51 #include "TextUnit.h"
52 #include "TrainUnit.h"
53 #include "Utilities.h"
54 #include "TrackUnit.h"
55 #include "AboutUnit.h"
56 #include <fstream>
57 #include <dirent.h>
58 #include <Filectrl.hpp> //to check whether directories exist
59 
60 // ---------------------------------------------------------------------------
61 #include <Vcl.HTMLHelpViewer.hpp> //added at v2.0.0 for access to the .chm help file
62 #pragma package(smart_init)
63 #pragma link "Vcl.HTMLHelpViewer" //added at v2.0.0 for access to the .chm help file
64 #pragma resource "*.dfm"
65 
67 
68 // Folder Names
69 const UnicodeString TInterface::RAILWAY_DIR_NAME = "Railways";
70 const UnicodeString TInterface::TIMETABLE_DIR_NAME = "Program timetables";
71 const UnicodeString TInterface::PERFLOG_DIR_NAME = "Performance logs";
72 const UnicodeString TInterface::SESSION_DIR_NAME = "Sessions";
73 const UnicodeString TInterface::IMAGE_DIR_NAME = "Images";
74 const UnicodeString TInterface::FORMATTEDTT_DIR_NAME = "Formatted timetables";
75 const UnicodeString TInterface::USERGRAPHICS_DIR_NAME = "Graphics";
76 
77 // ---------------------------------------------------------------------------
78 
79 __fastcall TInterface::TInterface(TComponent* Owner): TForm(Owner)
80 { // constructor
81  try
82  {
83  Screen->Cursor = TCursor(-11); // Hourglass;
84  DirOpenError = false;
85  AllSetUpFlag = false; // flag to prevent MasterClock from being enabled when application activates if there has been an error during
86  // initial setup
87  // MasterClock->Enabled = false;//keep this stopped until all set up (no effect here as form not yet created, made false in object insp)
88  // Visible = false; //keep the Interface form invisible until all set up (no effect here as form not yet created, made false in object insp)
90  // use GNU Major/Minor/Patch version numbering system, change for each published modification, Dev x = interim internal
91  // development stages (don't show on published versions)
92 
93  // check for presence of directories, creation failure probably indicates that the
94  // working folder is read-only
95  CurDir = GetCurrentDir();
96  if(!DirectoryExists(RAILWAY_DIR_NAME))
97  {
98  if(!CreateDir(RAILWAY_DIR_NAME))
99  {
100  DirOpenError = true;
101  }
102  }
103  if(!DirectoryExists(TIMETABLE_DIR_NAME))
104  {
105  if(!CreateDir(TIMETABLE_DIR_NAME))
106  {
107  DirOpenError = true;
108  }
109  }
110  if(!DirectoryExists(PERFLOG_DIR_NAME))
111  {
112  if(!CreateDir(PERFLOG_DIR_NAME))
113  {
114  DirOpenError = true;
115  }
116  }
117  if(!DirectoryExists(SESSION_DIR_NAME))
118  {
119  if(!CreateDir(SESSION_DIR_NAME))
120  {
121  DirOpenError = true;
122  }
123  }
124  if(!DirectoryExists(IMAGE_DIR_NAME))
125  {
126  if(!CreateDir(IMAGE_DIR_NAME))
127  {
128  DirOpenError = true;
129  }
130  }
131  if(!DirectoryExists(FORMATTEDTT_DIR_NAME))
132  {
133  if(!CreateDir(FORMATTEDTT_DIR_NAME))
134  {
135  DirOpenError = true;
136  }
137  }
138  if(!DirectoryExists(USERGRAPHICS_DIR_NAME))
139  {
140  if(!CreateDir(USERGRAPHICS_DIR_NAME))
141  {
142  DirOpenError = true;
143  }
144  }
145  if(DirOpenError)
146  {
147  ShowMessage("Failed to create one or more of folders: " + RAILWAY_DIR_NAME + ", " + TIMETABLE_DIR_NAME + ", " + PERFLOG_DIR_NAME + ", " +
149  "program operation may be restricted");
150  }
151 // ShowMessage("NOTE: APPDEACTIVATE etc Disabled in FormCreate");
152  SaveRailwayDialog->InitialDir = CurDir + "\\" + RAILWAY_DIR_NAME;
153  LoadRailwayDialog->InitialDir = CurDir + "\\" + RAILWAY_DIR_NAME;
154  TimetableDialog->InitialDir = CurDir + "\\" + TIMETABLE_DIR_NAME;
155  SaveTTDialog->InitialDir = CurDir + "\\" + TIMETABLE_DIR_NAME;
156  LoadSessionDialog->InitialDir = CurDir + "\\" + SESSION_DIR_NAME;
157  LoadUserGraphicDialog->InitialDir = CurDir + "\\" + USERGRAPHICS_DIR_NAME;
158 
159  Application->HelpFile = AnsiString(CurDir + "\\Help.chm"); // added at v2.0.0 for .chm help file
160 
161  MainMenu1->AutoHotkeys = maManual; // Embarcadero mod: to suppress '&' inclusion for underlined characters in menu items
162  PopupMenu->AutoHotkeys = maManual; // as above
163 
164  Utilities = new TUtilities;
165  RailGraphics = new TRailGraphics();
166 
167  int DispW = (Screen->Width - 64) / 16; // will truncate down to a multiple of 16 OK here as screen dimensions are accurate
168  int DispH = (Screen->Height - 192) / 16; // Interface dimensions are 16 too wide & 14 short in height
169  MainScreen->Width = DispW * 16;
170  MainScreen->Height = DispH * 16;
171 
174  Utilities->ScreenElementWidth = DispW;
176  HiddenScreen = new TImage(Interface);
177  HiddenScreen->Width = MainScreen->Width;
178  HiddenScreen->Height = MainScreen->Height;
182  Track = new TTrack;
183  AllRoutes = new TAllRoutes;
188  SelectBitmap = new Graphics::TBitmap;
189  SelectBitmap->PixelFormat = pf8bit;
190  SelectBitmap->Transparent = true;
195 
196  TrackInfoOnOffMenuItem->Caption = "Show"; // added here at v1.2.0 because dropped from ResetAll()
197  TrainStatusInfoOnOffMenuItem->Caption = "Hide Status"; // changed at v2.0.0 so normally visible
198  TrainTTInfoOnOffMenuItem->Caption = "Hide Timetable"; // as above
199  ResetAll(0);
200 
201  TempTTFileName = "";
202 
207 
208  RouteFlashDuration = 0.0;
209  PointsFlashDuration = 0.0;
210 
211  FloatingLabel->Color = clB4G5R5;
212  TrackElementPanel->Color = clB5G5R4;
213  InfoPanel->Color = clB4G5R5;
214 
215  SpeedButton1->Glyph->LoadFromResourceName(0, "gl1");
216  SpeedButton2->Glyph->LoadFromResourceName(0, "gl2");
217  SpeedButton3->Glyph->LoadFromResourceName(0, "gl3");
218  SpeedButton4->Glyph->LoadFromResourceName(0, "gl4");
219  SpeedButton5->Glyph->LoadFromResourceName(0, "gl5");
220  SpeedButton6->Glyph->LoadFromResourceName(0, "gl6");
221  SpeedButton7->Glyph->LoadFromResourceName(0, "gl7");
222  SpeedButton8->Glyph->LoadFromResourceName(0, "gl8");
223  SpeedButton9->Glyph->LoadFromResourceName(0, "gl9");
224  SpeedButton10->Glyph->LoadFromResourceName(0, "gl10");
225  SpeedButton11->Glyph->LoadFromResourceName(0, "gl11");
226  SpeedButton12->Glyph->LoadFromResourceName(0, "gl12");
227  SpeedButton13->Glyph->LoadFromResourceName(0, "gl13");
228  SpeedButton14->Glyph->LoadFromResourceName(0, "gl14");
229  SpeedButton15->Glyph->LoadFromResourceName(0, "gl15");
230  SpeedButton16->Glyph->LoadFromResourceName(0, "gl16");
231  SpeedButton18->Glyph->LoadFromResourceName(0, "gl18");
232  SpeedButton19->Glyph->LoadFromResourceName(0, "gl19");
233  SpeedButton20->Glyph->LoadFromResourceName(0, "gl20");
234  SpeedButton21->Glyph->LoadFromResourceName(0, "gl21");
235  SpeedButton22->Glyph->LoadFromResourceName(0, "gl22");
236  SpeedButton23->Glyph->LoadFromResourceName(0, "gl23");
237  SpeedButton24->Glyph->LoadFromResourceName(0, "gl24");
238  SpeedButton25->Glyph->LoadFromResourceName(0, "gl25");
239  SpeedButton26->Glyph->LoadFromResourceName(0, "gl26");
240  SpeedButton27->Glyph->LoadFromResourceName(0, "gl27");
241  SpeedButton28->Glyph->LoadFromResourceName(0, "gl28");
242  SpeedButton29->Glyph->LoadFromResourceName(0, "gl29");
243  SpeedButton30->Glyph->LoadFromResourceName(0, "gl30");
244  SpeedButton31->Glyph->LoadFromResourceName(0, "gl31");
245  SpeedButton32->Glyph->LoadFromResourceName(0, "gl32");
246  SpeedButton33->Glyph->LoadFromResourceName(0, "gl33");
247  SpeedButton34->Glyph->LoadFromResourceName(0, "gl34");
248  SpeedButton35->Glyph->LoadFromResourceName(0, "gl35");
249  SpeedButton36->Glyph->LoadFromResourceName(0, "gl36");
250  SpeedButton37->Glyph->LoadFromResourceName(0, "gl37");
251  SpeedButton38->Glyph->LoadFromResourceName(0, "gl38");
252  SpeedButton39->Glyph->LoadFromResourceName(0, "gl39");
253  SpeedButton40->Glyph->LoadFromResourceName(0, "gl40");
254  SpeedButton41->Glyph->LoadFromResourceName(0, "gl41");
255  SpeedButton42->Glyph->LoadFromResourceName(0, "gl42");
256  SpeedButton43->Glyph->LoadFromResourceName(0, "gl43");
257  SpeedButton44->Glyph->LoadFromResourceName(0, "gl44");
258  SpeedButton45->Glyph->LoadFromResourceName(0, "gl45");
259  SpeedButton46->Glyph->LoadFromResourceName(0, "gl46");
260  SpeedButton47->Glyph->LoadFromResourceName(0, "gl47");
261  SpeedButton48->Glyph->LoadFromResourceName(0, "gl48");
262  SpeedButton49->Glyph->LoadFromResourceName(0, "gl49");
263  SpeedButton50->Glyph->LoadFromResourceName(0, "gl50");
264  SpeedButton51->Glyph->LoadFromResourceName(0, "gl51");
265  SpeedButton52->Glyph->LoadFromResourceName(0, "gl52");
266  SpeedButton53->Glyph->LoadFromResourceName(0, "gl53");
267  SpeedButton54->Glyph->LoadFromResourceName(0, "gl54");
268  SpeedButton55->Glyph->LoadFromResourceName(0, "gl55");
269  SpeedButton56->Glyph->LoadFromResourceName(0, "gl56");
270  SpeedButton57->Glyph->LoadFromResourceName(0, "gl57");
271  SpeedButton58->Glyph->LoadFromResourceName(0, "gl58");
272  SpeedButton59->Glyph->LoadFromResourceName(0, "gl59");
273  SpeedButton60->Glyph->LoadFromResourceName(0, "gl60");
274  SpeedButton61->Glyph->LoadFromResourceName(0, "gl61");
275  SpeedButton62->Glyph->LoadFromResourceName(0, "gl62");
276  SpeedButton63->Glyph->LoadFromResourceName(0, "gl63");
277  SpeedButton64->Glyph->LoadFromResourceName(0, "gl64");
278  SpeedButton65->Glyph->LoadFromResourceName(0, "gl65");
279  SpeedButton66->Glyph->LoadFromResourceName(0, "gl66");
280  SpeedButton67->Glyph->LoadFromResourceName(0, "gl67");
281  SpeedButton68->Glyph->LoadFromResourceName(0, "gl68");
282  SpeedButton69->Glyph->LoadFromResourceName(0, "gl69");
283  SpeedButton70->Glyph->LoadFromResourceName(0, "gl70");
284  SpeedButton71->Glyph->LoadFromResourceName(0, "gl71");
285  SpeedButton72->Glyph->LoadFromResourceName(0, "gl72");
286  SpeedButton73->Glyph->LoadFromResourceName(0, "gl73");
287  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74");
288  SpeedButton75->Glyph->LoadFromResourceName(0, "gl75");
289  SpeedButton76->Glyph->LoadFromResourceName(0, "gl76");
290  SpeedButton77->Glyph->LoadFromResourceName(0, "gl77");
291  SpeedButton78->Glyph->LoadFromResourceName(0, "gl78");
292  SpeedButton79->Glyph->LoadFromResourceName(0, "gl79");
293  SpeedButton80->Glyph->LoadFromResourceName(0, "gl80");
294  SpeedButton81->Glyph->LoadFromResourceName(0, "gl81");
295  SpeedButton82->Glyph->LoadFromResourceName(0, "gl82");
296  SpeedButton83->Glyph->LoadFromResourceName(0, "gl83");
297  SpeedButton84->Glyph->LoadFromResourceName(0, "gl84");
298  SpeedButton85->Glyph->LoadFromResourceName(0, "gl85");
299  SpeedButton86->Glyph->LoadFromResourceName(0, "gl86");
300  SpeedButton87->Glyph->LoadFromResourceName(0, "gl87");
301  SpeedButton88->Glyph->LoadFromResourceName(0, "gl88set");
302  SpeedButton89->Glyph->LoadFromResourceName(0, "gl89set");
303  SpeedButton90->Glyph->LoadFromResourceName(0, "gl90set");
304  SpeedButton91->Glyph->LoadFromResourceName(0, "gl91set");
305  SpeedButton92->Glyph->LoadFromResourceName(0, "gl92set");
306  SpeedButton93->Glyph->LoadFromResourceName(0, "gl93set");
307  SpeedButton94->Glyph->LoadFromResourceName(0, "gl94set");
308  SpeedButton95->Glyph->LoadFromResourceName(0, "gl95set");
309  SpeedButton96->Glyph->LoadFromResourceName(0, "ConcourseGlyph");
310  SpeedButton97->Glyph->LoadFromResourceName(0, "gl97");
311  SpeedButton98->Glyph->LoadFromResourceName(0, "gl98");
312  SpeedButton99->Glyph->LoadFromResourceName(0, "gl99");
313  SpeedButton100->Glyph->LoadFromResourceName(0, "gl100");
314  SpeedButton101->Glyph->LoadFromResourceName(0, "gl101");
315  SpeedButton102->Glyph->LoadFromResourceName(0, "gl102");
316  SpeedButton103->Glyph->LoadFromResourceName(0, "gl103");
317  SpeedButton104->Glyph->LoadFromResourceName(0, "gl104");
318  SpeedButton105->Glyph->LoadFromResourceName(0, "gl105");
319  SpeedButton106->Glyph->LoadFromResourceName(0, "gl106");
320  SpeedButton107->Glyph->LoadFromResourceName(0, "gl107");
321  SpeedButton108->Glyph->LoadFromResourceName(0, "gl108");
322  SpeedButton109->Glyph->LoadFromResourceName(0, "gl109");
323  SpeedButton110->Glyph->LoadFromResourceName(0, "gl110");
324  SpeedButton111->Glyph->LoadFromResourceName(0, "gl111");
325  SpeedButton112->Glyph->LoadFromResourceName(0, "gl112");
326  SpeedButton113->Glyph->LoadFromResourceName(0, "gl113");
327  SpeedButton114->Glyph->LoadFromResourceName(0, "gl114");
328  SpeedButton115->Glyph->LoadFromResourceName(0, "gl115");
329  SpeedButton116->Glyph->LoadFromResourceName(0, "gl116");
330  SpeedButton117->Glyph->LoadFromResourceName(0, "gl117");
331  SpeedButton118->Glyph->LoadFromResourceName(0, "gl118");
332  SpeedButton119->Glyph->LoadFromResourceName(0, "gl119");
333  SpeedButton120->Glyph->LoadFromResourceName(0, "gl120");
334  SpeedButton121->Glyph->LoadFromResourceName(0, "gl121");
335  SpeedButton122->Glyph->LoadFromResourceName(0, "gl122");
336  SpeedButton123->Glyph->LoadFromResourceName(0, "gl123");
337  SpeedButton124->Glyph->LoadFromResourceName(0, "gl124");
338  SpeedButton125->Glyph->LoadFromResourceName(0, "gl125");
339  SpeedButton126->Glyph->LoadFromResourceName(0, "gl126");
340  SpeedButton127->Glyph->LoadFromResourceName(0, "gl127");
341  SpeedButton128->Glyph->LoadFromResourceName(0, "gl128");
342  SpeedButton129->Glyph->LoadFromResourceName(0, "gl129");
343  SpeedButton130->Glyph->LoadFromResourceName(0, "gl130");
344  SpeedButton131->Glyph->LoadFromResourceName(0, "gl131");
345  SpeedButton132->Glyph->LoadFromResourceName(0, "gl132");
346  SpeedButton133->Glyph->LoadFromResourceName(0, "gl133");
347  SpeedButton134->Glyph->LoadFromResourceName(0, "gl134");
348  SpeedButton135->Glyph->LoadFromResourceName(0, "gl135");
349  SpeedButton136->Glyph->LoadFromResourceName(0, "gl136");
350  SpeedButton137->Glyph->LoadFromResourceName(0, "gl137");
351  SpeedButton138->Glyph->LoadFromResourceName(0, "gl138");
352  SpeedButton139->Glyph->LoadFromResourceName(0, "gl139");
353  SpeedButton140->Glyph->LoadFromResourceName(0, "gl140");
354  SpeedButton141->Glyph->LoadFromResourceName(0, "gl141");
355  SpeedButton142->Glyph->LoadFromResourceName(0, "gl142");
356  SpeedButton143->Glyph->LoadFromResourceName(0, "gl143");
357  SpeedButton145->Glyph->LoadFromResourceName(0, "gl145");
358  SpeedButton146->Glyph->LoadFromResourceName(0, "gl146");
359  // below not in RailGraphics
360  SpeedButton144->Glyph->LoadFromResourceName(0, "LCGlyph");
361 
362  AddPrefDirButton->Glyph->LoadFromResourceName(0, "AddPrefDir");
363  AddTextButton->Glyph->LoadFromResourceName(0, "AddText");
364  AddTrackButton->Glyph->LoadFromResourceName(0, "AddTrack");
365  AutoSigsButton->Glyph->LoadFromResourceName(0, "AutoSig");
366  CallingOnButton->Glyph->LoadFromResourceName(0, "CallingOn");
367  DeleteAllPrefDirButton->Glyph->LoadFromResourceName(0, "ClearAllPrefDir");
368  DeleteOnePrefDirButton->Glyph->LoadFromResourceName(0, "ClearOnePrefDir");
369  ExitOperationButton->Glyph->LoadFromResourceName(0, "Exit");
370  ExitPrefDirButton->Glyph->LoadFromResourceName(0, "Exit");
371  ExitTrackButton->Glyph->LoadFromResourceName(0, "Exit");
372  ExitTTModeButton->Glyph->LoadFromResourceName(0, "Exit");
373  FontButton->Glyph->LoadFromResourceName(0, "FontGraphic");
374  HomeButton->Glyph->LoadFromResourceName(0, "Home");
375  LocationNameButton->Glyph->LoadFromResourceName(0, "NameLocs");
376  MoveTextOrGraphicButton->Glyph->LoadFromResourceName(0, "MoveTextOrGraphic");
377  NewHomeButton->Glyph->LoadFromResourceName(0, "NewHome");
378  UnrestrictedButton->Glyph->LoadFromResourceName(0, "NonSig");
379  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
380  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel");
381  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
382  PresetAutoSigRoutesButton->Glyph->LoadFromResourceName(0, "PresetAutoSigRoutes");
383  RouteCancelButton->Glyph->LoadFromResourceName(0, "RouteCancel");
384  SaveRailwayPDPButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // PrefDirPanel
385  SaveRailwayBaseModeButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // OperatingPanel
386  SaveRailwayTBPButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // TrackBuildPanel
387  SaveSessionButton->Glyph->LoadFromResourceName(0, "SaveSession");
388  ScreenDownButton->Glyph->LoadFromResourceName(0, "BlackArrowDown");
389  ScreenGridButton->Glyph->LoadFromResourceName(0, "ScreenGrid");
390  ScreenLeftButton->Glyph->LoadFromResourceName(0, "BlackArrowLeft");
391  ScreenRightButton->Glyph->LoadFromResourceName(0, "BlackArrowRight");
392  ScreenUpButton->Glyph->LoadFromResourceName(0, "BlackArrowUp");
393  SetGapsButton->Glyph->LoadFromResourceName(0, "ConnectGaps");
394  SetLengthsButton->Glyph->LoadFromResourceName(0, "SetDists");
395  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
396  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect"); // new at version 0.6
397  SigPrefButton->Glyph->LoadFromResourceName(0, "PrefSig");
398  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
399  TrackOKButton->Glyph->LoadFromResourceName(0, "Validate");
400  TTClockAdjButton->Glyph->LoadFromResourceName(0, "TTClock");
401  UserGraphicButton->Glyph->LoadFromResourceName(0, "PictureImage");
402 
403  BufferAttentionImage->Picture->Bitmap->LoadFromResourceName(0, "BufferWarning");
404  CallOnImage->Picture->Bitmap->LoadFromResourceName(0, "CallingOn");
405  CrashImage->Picture->Bitmap->LoadFromResourceName(0, "CrashWarning");
406  DerailImage->Picture->Bitmap->LoadFromResourceName(0, "DerailWarning");
407  SignalStopImage->Picture->Bitmap->LoadFromResourceName(0, "SignalStopWarning");
408  SPADImage->Picture->Bitmap->LoadFromResourceName(0, "SPADWarning");
409  TrainFailedImage->Picture->Bitmap->LoadFromResourceName(0, "TrainFailedWarning"); // new at v2.4.0
410 
411  DistanceKey->Picture->Bitmap->LoadFromResourceName(0, "DistanceKey");
412  PrefDirKey->Picture->Bitmap->LoadFromResourceName(0, "PrefDirKey");
413 
414  TrackLinkedImage->Picture->Bitmap->LoadFromResourceName(0, "TrackLinkedGraphic");
415  TrackNotLinkedImage->Picture->Bitmap->LoadFromResourceName(0, "TrackNotLinkedGraphic");
416  GapsNotSetImage->Picture->Bitmap->LoadFromResourceName(0, "GapsNotSetGraphic");
417  GapsSetImage->Picture->Bitmap->LoadFromResourceName(0, "GapsSetGraphic");
418  LocationNamesNotSetImage->Picture->Bitmap->LoadFromResourceName(0, "LocNamesNotSetGraphic");
419  LocationNamesSetImage->Picture->Bitmap->LoadFromResourceName(0, "LocNamesSetGraphic");
420 
421  SigsOnLeftImage1->Picture->Bitmap->LoadFromResourceName(0, "SigsOnLeft");
422  SigsOnLeftImage2->Picture->Bitmap->LoadFromResourceName(0, "SigsOnLeft");
423  SigsOnLeftImage1->Transparent = true;
424  SigsOnLeftImage2->Transparent = true;
425  SigsOnLeftImage1->Picture->Bitmap->TransparentColor = clB5G5R5;
426  SigsOnLeftImage2->Picture->Bitmap->TransparentColor = clB5G5R5;
427  SigsOnRightImage1->Picture->Bitmap->LoadFromResourceName(0, "SigsOnRight");
428  SigsOnRightImage2->Picture->Bitmap->LoadFromResourceName(0, "SigsOnRight");
429  SigsOnRightImage1->Transparent = true;
430  SigsOnRightImage2->Transparent = true;
431  SigsOnRightImage1->Picture->Bitmap->TransparentColor = clB5G5R5;
432  SigsOnRightImage2->Picture->Bitmap->TransparentColor = clB5G5R5;
433 
434 /* Don't need this - load icon directly into both Interface form & Application (via Project - Options - Application - Load Icon)
435  RailwayIcon = new TPicture;
436  RailwayIcon->Icon->LoadFromResourceName(0, "Icon1.ico");
437  Icon = RailwayIcon->Icon;
438  Application->Icon = RailwayIcon->Icon;
439 */
440 
441  AnsiString NL = '\n';
442  const AnsiString TTLabelStr1 = "Start new train" + NL + "Start new service from a split" + NL + "Start new service from another service" + NL +
443  "Start new non-repeating shuttle finish service" + NL + "Start new shuttle train at a timetabled stop" + NL +
444  "Start new shuttle service from a feeder";
445 
446  const AnsiString TTLabelStr2 = "Pass" + NL + "Be joined by another train" + NL + "Front split" + NL + "Rear split" + NL + "Change direction of train";
447 
448  const AnsiString TTLabelStr3 = "Finish && form a new service" + NL + "Finish && join another train" + NL + "Finish && exit railway" + NL +
449  "Finish && repeat shuttle, finally remain here" + NL + "Finish && repeat shuttle, finally form a finishing service" + NL +
450  "Finish non-repeating shuttle feeder service" + NL + "Finish && remain here";
451 
452  const AnsiString TTLabelStr4 = "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL +
453  "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + " " + NL + "R";
454 
455  const AnsiString TTLabelStr5 = "HH:MM ';' Location" + NL + "HH:MM ';' HH:MM ';' Location";
456 
457  const AnsiString TTLabelStr6 = "+ rear element ID - space - front element ID [+ optional ';S']" + NL + "+ ref. of the train that splits" + NL +
458  "+ other service ref." + NL + "+ shuttle service ref." + NL + "+ rear element ID - space - front element ID ';' linked shuttle ref." + NL +
459  "+ linked shuttle service ref. ';' feeder service ref." + NL + "+ location" + NL + "+ joining train ref." + NL + "+ new service ref." + NL +
460  "+ new service ref." + NL + " " + NL + "+ new service ref." + NL + "+ ref. of train to join" + NL +
461  "+ list of valid exit element IDs (at least 1) separated by spaces" + NL + "+ linked shuttle service ref.";
462 
463  const AnsiString TTLabelStr7 = "Arrival OR departure time (program will determine which from the context) + location." + NL +
464  "Arrival time, departure time (with no events between) + location";
465 
466  const AnsiString TTLabelStr9 = "Timetable entries" + NL + "(service references etc.)";
467  const AnsiString TTLabelStr11 = "Timetable" + NL + "start time";
468 
469  const AnsiString TTLabelStr12 = "NB: WITHIN SERVICES commas must" + NL + "not be used (have special meanings)," + NL +
470  "and semicolons may only be used to" + NL + "separate service components.";
471 
472  const AnsiString TTLabelStr13 = "+ linked shuttle service ref. ';' finishing service ref." + NL + "+ linked shuttle service ref.";
473 
474  const AnsiString TTLabelStr15 = "Repeat the service + ';' minutes between repeats ';' digit increment ';' number of repeats (last line of service)";
475 
476  TTLabel1->Caption = TTLabelStr1;
477  TTLabel2->Caption = TTLabelStr2;
478  TTLabel3->Caption = TTLabelStr3;
479  TTLabel4->Caption = TTLabelStr4;
480  TTLabel5->Caption = TTLabelStr5;
481  TTLabel6->Caption = TTLabelStr6;
482  TTLabel7->Caption = TTLabelStr7;
483  TTLabel9->Caption = TTLabelStr9;
484  TTLabel11->Caption = TTLabelStr11;
485  TTLabel12->Caption = TTLabelStr12;
486  TTLabel13->Caption = TTLabelStr13;
487  TTLabel15->Caption = TTLabelStr15;
488 
489  // pick up transparent colour from file if there is one & set it to the stored value if it's valid else set to black
490 
491  AnsiString ColourStr = "";
492  std::ifstream ColFile((CurDir + "\\Background.col").c_str());
493  if(ColFile.fail())
494  {
495  Utilities->clTransparent = clB0G0R0; // default black background;
496  }
497  else
498  {
499  if(!(Utilities->CheckAndReadFileString(ColFile, ColourStr)))
500  {
501  Utilities->clTransparent = clB0G0R0; // default black background;
502  }
503  else if((ColourStr != "white") && (ColourStr != "black") && (ColourStr != "blue"))
504  {
505  Utilities->clTransparent = clB0G0R0; // default black background;
506  }
507  else
508  {
509  if(ColourStr == "white")
510  {
511  Utilities->clTransparent = TColor(0xFFFFFF);
512  }
513  else if(ColourStr == "blue")
514  {
515  Utilities->clTransparent = TColor(0x330000);
516  }
517  else
518  {
519  Utilities->clTransparent = TColor(0);
520  }
521  ColFile.close(); // added at v2.3.0, should have been in earlier
522  }
523  }
524 
525  Utilities->RHSignalFlag = false; // new at v2.3.0 for RH signals, always left hand on startup
526  AnsiString RHSigStr = "";
527  std::ifstream SignalFile((CurDir + "\\Signal.hnd").c_str());
528  if(SignalFile.fail())
529  {
530  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
531  SigsOnLeftImage1->Visible = true;
532  SigsOnLeftImage2->Visible = true;
533  SigsOnRightImage1->Visible = false;
534  SigsOnRightImage2->Visible = false;
535  SignalFile.close(); // close ifstream & open ofstream
536  std::ofstream SignalFile((CurDir + "\\Signal.hnd").c_str());
537  if(!SignalFile.fail()) // if it does fail then it will revert to LHS anyway on next load unless select RH sigs
538  {
539  Utilities->SaveFileString(SignalFile, "LHSignals");
540  }
541  SignalFile.close();
542  }
543  else
544  {
545  if(Utilities->CheckAndReadFileString(SignalFile, RHSigStr)) // if it fails then do nothing
546  {
547  if(RHSigStr == "RHSignals")
548  {
549  RailGraphics->ConvertSignalsToOppositeHand(1); // always left hand initially when start program
550  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Left Hand Signals";
552  {
554  }
555  else
556  {
558  }
559  SigImagePanel->Caption = "Signals will be on the right hand side of the track";
560  SigsOnLeftImage1->Visible = false;
561  SigsOnLeftImage2->Visible = false;
562  SigsOnRightImage1->Visible = true;
563  SigsOnRightImage2->Visible = true;
564  SignalFile.close();
565  }
566  else
567  {
568  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
569  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
570  SigsOnLeftImage1->Visible = true;
571  SigsOnLeftImage2->Visible = true;
572  SigsOnRightImage1->Visible = false;
573  SigsOnRightImage2->Visible = false;
574  SignalFile.close(); // close ifstream & open ofstream
575  std::ofstream SignalFile((CurDir + "\\Signal.hnd").c_str());
576  if(!SignalFile.fail()) // if it does fail then it will revert to LHS anyway on next load unless select RH sigs
577  {
578  Utilities->SaveFileString(SignalFile, "LHSignals");
579  }
580  SignalFile.close();
581  }
582  }
583  }
584 
585  SelectBitmap->TransparentColor = Utilities->clTransparent;
586  RailGraphics->ChangeAllTransparentColours(Utilities->clTransparent, clB5G5R5); // original colour is as loaded at this stage - white
588  TextBox->Color = clB3G3R3;
590 
591  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
592  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
593 
594  std::ifstream SplashFile((CurDir + "\\GNU").c_str());
595  if(SplashFile.fail())
596  {
597  ShowMessage(
598  "This program is free software released under the terms of the GNU General Public License Version 3, as published by the Free Software Foundation. It may be used or redistributed in accordance with that license and is released in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details - you should have received a copy along with this program but if not see <http://www.gnu.org/licenses/>.");
599  std::ofstream SplashFile((CurDir + "\\GNU").c_str());
600  if(!SplashFile.fail())
601  SplashFile.close();
602  }
603 
604  if((Screen->Width < 1024) || (Screen->Height < 768))
605  {
606  ShowMessage("Please note that this program works best with a screen resolution of at least 1024 x 768. Please change if possible");
607  }
608 
609  SkipFormResizeEvent = true; // added at v2.1.0
610  MasterClock->Enabled = true;
611  Visible = true; // make Interface form visible (set to false at design time) autocalls FormResize so it is skipped
612  WindowState = wsMaximized; // need this for full screen at start autocalls FormResize so it is skipped
613  MTBFEditBox->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30; // new v2.4.0 30 is to place it above the positional panel
614  // has to come after Visible = true or doesn't show
615  MTBFLabel->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30 - 55; // new v2.4.0 placed above and to the left of MTBFEditBox
616  PositionalPanel->Left = MainScreen->Left + MainScreen->Width; // changed at v2.4.0
617  PositionalPanel->Top = MainScreen->Top; // changed at v2.4.0
618  PositionalPanel->Height = MainScreen->Height; // changed at v2.4.0
619  AllSetUpFlag = true;
620  MissedTicks = 0;
621  TotalTicks = 0;
623  SetLevel1Mode(131); // to reset background colour mode menu choices
624  Screen->Cursor = TCursor(-2); // Arrow
625  SkipFormResizeEvent = false; // added at v2.1.0
626  SelectedGraphicFileName = ""; // only set to null here so always has a value after use LoadUserGraphic
627 
628  FloatingPanel->Color = TColor(0xF0FFFF); // new v2.2.0, corrects floating panel background colour in Windows 10
629  PerformancePanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
630  OperatorActionPanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
631  DevelopmentPanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
632  TTStartTimeBox->Color = TColor(0x99FFFF); // cream
633  HighlightPanel->Color = TColor(0x33CCFF);
635  MTBFEditBox->Visible = false; // new at v2.4.0
636  MTBFLabel->Visible = false;
639  TTStartTimePtr = 0;
640  TTFirstServicePtr = 0;
641  TTLastServicePtr = 0;
642 
643  LastNonCtrlOrShiftKeyDown = -1; //set to no key
644 
645  SigImagePanel->Left = (Interface->Width - SigImagePanel->Width) / 2; // added for v2.3.0
646 
647  // below added at v2.4.0 so able to load session files with the correct decimal point
648  Utilities->DecimalPoint = '.'; // default case is full stop
649  char *LocalNumericInformation = setlocale(LC_NUMERIC, ""); // need this to set lconv to the environment's numeric format
651  if(LocalNumericInformation == "") // call failed, don't change decimal point in Utilities.cpp
652  {
653  Utilities->SetLocaleResultOK = false;
654  }
655  struct lconv Locale; // store this structure in memory (accessed via locale.h in Utilities.h)
656  struct lconv *conv = &Locale;
657  // read the locality conversion structure
658  conv = localeconv(); // this is what updates the structure
659  Utilities->DecimalPoint = conv->decimal_point[0];
660  }
661 
662  catch(const EFOpenError &e)
663  {
664  TMsgDlgButtons But;
665  But << mbOK;
666  MessageDlg(e.Message + " - program must terminate", mtError, But, 0);
667  Application->Terminate();
668  }
669 
670  catch(const Exception &e)
671  {
672  TMsgDlgButtons But;
673  But << mbOK;
674  AnsiString Message = "A fatal error occurred during the program setup process, the program must terminate. Message = " + e.Message;
675  MessageDlg(Message, mtError, But, 0); // this message given first in case can't create the error log
676  ErrorLog(115, e.Message);
677  Application->Terminate();
678  }
679 }
680 
681 // ---------------------------------------------------------------------------
682 
684 { // destructor
685  try
686  {
687  SkipFormResizeEvent = true; // added at v2.1.0
688  delete NonSigRouteStartMarker;
689  delete SigRouteStartMarker;
690  delete AutoRouteStartMarker;
691  delete PointFlash;
692  delete SelectBitmap;
693  delete TrainController;
694  delete EveryPrefDir;
695  delete ConstructRoute;
696  delete ConstructPrefDir;
697  delete AllRoutes;
698  delete Track;
699  delete TextHandler;
700  delete HiddenDisplay;
701  delete HiddenScreen;
702  delete Display;
703  delete RailGraphics;
704  delete Utilities;
705  }
706  catch(const Exception &e)
707  {
708  ErrorLog(116, e.Message);
709  }
710 }
712 
713 // ---------------------------------------------------------------------------
714 
715 void __fastcall TInterface::FormCreate(TObject *Sender)
716 { // these functions have to be defined here to take effect when application activated & deactivated
717  try
718  {
719  Application->OnDeactivate = AppDeactivate;
720  Application->OnActivate = AppActivate;
721  }
722  catch(const Exception &e)
723  {
724  ErrorLog(117, e.Message);
725  }
726 }
727 
728 // ---------------------------------------------------------------------------
729 
730 void __fastcall TInterface::AppDeactivate(TObject *Sender)
731 { // pause operation if operating & stop the master clock
732  try
733  {
735  {
736  if(Track->RouteFlashFlag) // in case route building - cancels the route, freezes otherwise - reported
737  { // by Matt Blades 30/06/11
741  Screen->Cursor = TCursor(-2); // Arrow
742  Track->RouteFlashFlag = false;
743  ClearandRebuildRailway(48); // to get rid of displayed route
744  }
745  if(Track->PointFlashFlag)
746  // added at v1.3.1 to prevent lockup for flashing points when deactivates. Notified by Ian Walker in his email of 25/03/13.
747  {
749  Track->PointFlashFlag = false;
751  Screen->Cursor = TCursor(-2); // Arrow
752  }
755  }
756  MasterClock->Enabled = false;
757  }
758  catch(const Exception &e)
759  {
760  ErrorLog(118, e.Message);
761  }
762 }
763 
764 // ---------------------------------------------------------------------------
765 
766 void __fastcall TInterface::AppActivate(TObject *Sender)
767 { // restart the master clock providing Interface constructor has run
768  try
769  {
770  if(AllSetUpFlag)
771  {
772  MasterClock->Enabled = true;
773  }
774  }
775  catch(const Exception &e)
776  {
777  ErrorLog(119, e.Message);
778  }
779 }
780 
781 // ---------------------------------------------------------------------------
782 
783 UnicodeString TInterface::GetVersion()
784 {
785  DWORD VersionHandle;
786  DWORD VersionSize;
787  LPBYTE pBuffer;
788  UnicodeString strVersion = L"N/A";
789 
790  VersionSize = GetFileVersionInfoSizeW(Application->ExeName.c_str(), &VersionHandle);
791  if(VersionSize)
792  {
793  pBuffer = new BYTE[VersionSize];
794 
795  if(GetFileVersionInfoW(Application->ExeName.c_str(), VersionHandle, VersionSize, pBuffer))
796  {
797  VS_FIXEDFILEINFO *fi;
798  UINT buflen;
799 
800  // uncomment strVersion and HIWORD alternates below when future CI implemented: sas@2.1.0
801  if(VerQueryValueW(pBuffer, L"\\", (void**)&fi, &buflen))
802  {
803  // strVersion.sprintf(L"%d.%d.%d (Build %d)",
804  strVersion.sprintf(L"%d.%d.%d", HIWORD(fi->dwFileVersionMS), LOWORD(fi->dwFileVersionMS), HIWORD(fi->dwFileVersionLS)
805  // HIWORD(fi->dwFileVersionLS), LOWORD(fi->dwFileVersionLS)
806  );
807  }
808  }
809 
810  delete[]pBuffer;
811  }
812 
813  return L" v" + strVersion;
814 }
815 
816 // ---------------------------------------------------------------------------
817 // Track Build Interface
818 // ---------------------------------------------------------------------------
819 void __fastcall TInterface::BuildTrackMenuItemClick(TObject *Sender) // Mode Menu Item
820 {
821  try
822  {
823  TrainController->LogEvent("BuildTrackMenuItemClick");
824  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BuildTrackMenuItemClick");
826  SetLevel1Mode(0);
827  Utilities->CallLogPop(1159);
828  }
829  catch(const Exception &e)
830  {
831  ErrorLog(120, e.Message);
832  }
833 }
834 // ---------------------------------------------------------------------------
835 
836 void __fastcall TInterface::AddTrackButtonClick(TObject *Sender)
837 {
838  try
839  {
840  TrainController->LogEvent("AddTrackButtonClick");
841  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddTrackButtonClick");
843  SetLevel1Mode(38);
846  Utilities->CallLogPop(1162);
847  }
848  catch(const Exception &e)
849  {
850  ErrorLog(121, e.Message);
851  }
852 }
853 
854 // ---------------------------------------------------------------------------
855 void __fastcall TInterface::SpeedButtonClick(TObject *Sender)
856 {
857  try
858  {
859  TrainController->LogEvent("SpeedButtonClick");
860  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedButtonClick");
861  if(((TSpeedButton*)Sender)->Down)
862  {
863  CurrentSpeedButton = (TSpeedButton*)Sender;
864 // TrainController->LogEvent("SpeedButtonClick, " + CurrentSpeedButton->Tag); //v 1.3.1 - using non-AnsiString CurrentSpeedButton->Tag sends (for an unknown reason) a completely wrong string to LogEvent, usually "...(behind this message)"
865  TrainController->LogEvent("SpeedButtonClick, " + AnsiString(CurrentSpeedButton->Tag)); // new version //use for v1.3.2
866  }
867  else
868  CurrentSpeedButton = 0;
869  SelectionValid = false;
870  ReselectMenuItem->Enabled = false;
871  Utilities->CallLogPop(1163);
872  }
873  catch(const Exception &e)
874  {
875  ErrorLog(122, e.Message);
876  }
877 }
878 
879 // ---------------------------------------------------------------------------
880 void __fastcall TInterface::TrackOKButtonClick(TObject *Sender)
881 {
882  try
883  {
884  TrainController->LogEvent("TrackOKButtonClick");
885  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrackOKButtonClick");
886  SelectionValid = false;
888  bool LocError;
889  int HLoc, VLoc;
890  // erase any corrupted PrefDirs then rebuild track & PrefDir vectors
891 // EveryPrefDir->EraseCorruptedElementsAfterTrackBuild(); not needed after dispensed with blank track elements for erased elements
892  if(!(Track->TryToConnectTrack(0, LocError, HLoc, VLoc, true))) // true for give messages
893  // if successful repositions TrackVector & builds TrackMap
894  {
895  if(LocError) // links not complete or other error - show offending element
896  {
897  while((Display->DisplayOffsetH - HLoc) > 0)
898  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
899  while((HLoc - Display->DisplayOffsetH) > (Utilities->ScreenElementWidth - 1))
901  while((Display->DisplayOffsetV - VLoc) > 0)
902  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
903  while((VLoc - Display->DisplayOffsetV) > (Utilities->ScreenElementHeight - 1))
906  Display->InvertElement(0, HLoc * 16, VLoc * 16);
907  ShowMessage("Incomplete track or other error - see inverted element (may be behind this message)");
908  ClearandRebuildRailway(1); // to clear inversion
910  SetLevel1Mode(39);
911  Level2TrackMode = AddTrack; // go to add track regardless of where started from
913  Utilities->CallLogPop(0);
914  return;
915  }
916  else
917  { // reach here if there are no track elements
918  ShowMessage("Unable to set any track links");
920  SetLevel1Mode(40);
922  SetLevel2TrackMode(4); // go to add track regardless of where started from
923  Utilities->CallLogPop(1);
924  return;
925  }
926  }
927  else
928  {
929  // success ('TrackFinished' set in TryToConnectTrack)
930  EveryPrefDir->RebuildPrefDirVector(0); // from TrackMap
931  ShowMessage("Successful Completion");
932  }
933 // success if reach here ('TrackFinished' set in TryToConnectTrack)
935  {
937  SetLevel1Mode(41);
939  }
940  else
941  {
943  SetLevel1Mode(36); // back to TrackMode if not in AddTrack mode
944  }
945  Utilities->CallLogPop(2);
946  }
947  catch(const Exception &e)
948  {
949  ErrorLog(3, e.Message);
950  }
951 }
952 
953 // ---------------------------------------------------------------------------
954 void __fastcall TInterface::SetGapsButtonClick(TObject *Sender)
955 {
956  try
957  {
958  TrainController->LogEvent("SetGapsButtonClick");
959  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SetGapsButtonClick");
960  SelectionValid = false;
961  ReselectMenuItem->Enabled = false;
963  SetLevel1Mode(42);
966  Utilities->CallLogPop(1164);
967  }
968  catch(const Exception &e)
969  {
970  ErrorLog(123, e.Message);
971  }
972 }
973 
974 // ---------------------------------------------------------------------------
975 void __fastcall TInterface::AddTextButtonClick(TObject *Sender)
976 {
977  try
978  {
979  TrainController->LogEvent("AddTextButtonClick");
980  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddTextButtonClick");
982  SetLevel1Mode(43);
985  Utilities->CallLogPop(1165);
986  }
987  catch(const Exception &e)
988  {
989  ErrorLog(124, e.Message);
990  }
991 }
992 
993 // ---------------------------------------------------------------------------
994 void __fastcall TInterface::MoveTextOrGraphicButtonClick(TObject *Sender)
995 {
996  try
997  {
998  TrainController->LogEvent("MoveTextOrGraphicButtonClick");
999  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTextOrGraphicButtonClick");
1001  SetLevel1Mode(44);
1003  SetLevel2TrackMode(8);
1004  Utilities->CallLogPop(1166);
1005  }
1006  catch(const Exception &e)
1007  {
1008  ErrorLog(125, e.Message);
1009  }
1010 }
1011 
1012 // ---------------------------------------------------------------------------
1013 void __fastcall TInterface::TextBoxKeyPress(TObject *Sender, char &Key)
1014 {
1015  try
1016  {
1017  TrainController->LogEvent("TextBoxKeyPress," + AnsiString(Key));
1018  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TextBoxKeyPress," + AnsiString(Key));
1019  if(Key == '\x0D') // CR
1020  {
1021  if(TextBox->Text != "") // if blank then don't save
1022  {
1023  if(Display->GetFont()->Color == clB5G5R5) // white
1024  {
1025  TFont *TempFont = new TFont;
1026  TempFont->Assign(Display->GetFont());
1027  TempFont->Color = clB0G0R0; // change to black for vector & saving
1028  Display->SetFont(TempFont);
1029  delete TempFont;
1030  }
1031  TFont *DisplayFont = Display->GetFont();
1032  TTextItem TempText = TTextItem(Text_X, Text_Y, TextBox->Text, DisplayFont);
1033  TempText.Font = DisplayFont; // may have been changed in above constructor when returned as reference
1035  }
1036  EditMenu->Enabled = true;
1037  TextBox->Visible = false;
1038  SetLevel2TrackMode(56); // to enable 'move text' if first text item added
1039  }
1040  else if(Key == '\x1B') // escape
1041  {
1042  TextBox->Visible = false;
1043  }
1044  Utilities->CallLogPop(3);
1045  }
1046  catch(const Exception &e)
1047  {
1048  ErrorLog(4, e.Message);
1049  }
1050 }
1051 
1052 // ---------------------------------------------------------------------------
1053 void __fastcall TInterface::LocationNameButtonClick(TObject *Sender)
1054 {
1055  try
1056  {
1057  TrainController->LogEvent("LocationNameButtonClick");
1058  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameButtonClick");
1060  SetLevel1Mode(45);
1062  SetLevel2TrackMode(9);
1063  Utilities->CallLogPop(1167);
1064  }
1065  catch(const Exception &e)
1066  {
1067  ErrorLog(126, e.Message);
1068  }
1069 }
1070 
1071 // ---------------------------------------------------------------------------
1072 void __fastcall TInterface::LocationNameKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
1073 {
1074  try
1075  {
1076  TrainController->LogEvent("LocationNameKeyUp," + AnsiString(Key));
1077  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameKeyUp," + AnsiString(Key));
1078  if(Track->LNPendingList.empty())
1079  {
1080  ShowMessage("Error, location name being entered without an entry in LNPendingList");
1082  SetLevel1Mode(46);
1084  SetLevel2TrackMode(10);
1085  Utilities->CallLogPop(4);
1086  return;
1087  }
1088  if(Key == '\x1B') // escape
1089  {
1090  Track->LNPendingList.clear(); // get rid of existing entry
1092  SetLevel1Mode(47);
1094  SetLevel2TrackMode(11);
1095  Utilities->CallLogPop(5);
1096  return;
1097  }
1098  if(Key == '\x0D')
1099  {
1100  Screen->Cursor = TCursor(-11); // Hourglass;
1102  AnsiString ExistingName;
1103  if(Track->LNPendingList.front() > -1)
1104  ExistingName = Track->InactiveTrackElementAt(27, Track->LNPendingList.front()).LocationName;
1105  else
1106  ExistingName = Track->TrackElementAt(425, -1 - (Track->LNPendingList.front())).LocationName;
1107  if(Track->LocationNameAllocated(1, LocationNameTextBox->Text) && (ExistingName != LocationNameTextBox->Text))
1108  { // name allocated to a different location
1109  UnicodeString MessageStr = UnicodeString("Another location named '") + LocationNameTextBox->Text +
1110  UnicodeString("' already exists. If you continue its name will be erased. Do you wish to continue?");
1111  int button = Application->MessageBox(MessageStr.c_str(), L"Warning!", MB_YESNO | MB_ICONWARNING);
1112  if(button == IDNO)
1113  {
1114  Track->LNPendingList.clear(); // get rid of existing entry
1115  Screen->Cursor = TCursor(-2); // Arrow
1117  SetLevel1Mode(48);
1119  SetLevel2TrackMode(12);
1120  Utilities->CallLogPop(6);
1121  return;
1122  }
1124  Track->EnterLocationName(1, LocationNameTextBox->Text, false);
1125  int HPos, VPos;
1126  bool UseExistingPosition = false;
1127  if(EraseLocationNameText(0, LocationNameTextBox->Text, HPos, VPos))
1128  {;
1129  } // condition not used
1130  // above may be redundant at v1.1.0 due to name erase in EnterLocationName
1131  // but, the location to be named may also have an existing name, in which case that needs to be erased
1132  // and the position re-used
1133  if(ExistingName != "")
1134  {
1135  if(EraseLocationNameText(3, ExistingName, HPos, VPos))
1136  UseExistingPosition = true; // may be redundant at v1.1.0 due to name erase in EnterLocationName
1137  }
1138  AddLocationNameText(0, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1139  Screen->Cursor = TCursor(-2); // Arrow
1141  SetLevel1Mode(49);
1143  SetLevel2TrackMode(13);
1144  Utilities->CallLogPop(7);
1145  return;
1146  }
1147  else if(Track->LocationNameAllocated(2, LocationNameTextBox->Text) && (ExistingName == LocationNameTextBox->Text))
1148  { // same name being entered again
1149  Track->LNPendingList.clear(); // get rid of existing entry as the location already has this name
1150  // but in case the name is not already in text vector erase it and re-add it
1151  // if it wasn't in the vector erasing it has no effect
1152  int HPos, VPos;
1153  bool UseExistingPosition = false;
1154  if(EraseLocationNameText(2, LocationNameTextBox->Text, HPos, VPos))
1155  UseExistingPosition = true;
1156  // above may be redundant at v1.1.0 due to name erase in EnterLocationName
1157  AddLocationNameText(2, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1158  Screen->Cursor = TCursor(-2); // Arrow
1160  SetLevel1Mode(50);
1162  SetLevel2TrackMode(14);
1163  Utilities->CallLogPop(8);
1164  return;
1165  }
1166  else
1167  { // either a new name for an unnamed location, or a different name for a named location
1168  // check validity of entry
1169  AnsiString LocStr = LocationNameTextBox->Text;
1170  LocStr = LocStr.Trim(); // strip leading & trailing spaces, and control characters
1171  LocationNameTextBox->Text = LocStr; // reset this as used below
1172 /* drop this, now covered by ...Trim() above
1173  //strip leading spaces
1174  while((LocStr != "") && (LocStr[1] == ' '))
1175  {
1176  LocStr = LocStr.SubString(2, LocStr.Length()-1);
1177  }
1178 */
1179  if((LocStr != "") && (LocStr[1] >= '0') && (LocStr[1] <= '9')) // can't begin with a number
1180  {
1181  Screen->Cursor = TCursor(-2); // Arrow
1182  ShowMessage("Location name can't begin with a number");
1184  SetLevel1Mode(51);
1186  SetLevel2TrackMode(15);
1187  Utilities->CallLogPop(776);
1188  return;
1189  }
1190  if(LocStr.Length() > 50)
1191  {
1192  Screen->Cursor = TCursor(-2); // Arrow
1193  ShowMessage("Location name too long, 50 characters maximum");
1195  SetLevel1Mode(122);
1197  SetLevel2TrackMode(55);
1198  Utilities->CallLogPop(1735);
1199  return;
1200  }
1201  for(int x = 1; x <= LocStr.Length(); x++)
1202  {
1203  char Ch = LocStr[x];
1204  if((Ch != ' ') && (Ch != '&') && (Ch != '(') && (Ch != ')') && (Ch != ':') && (Ch != 39) && (Ch != '.') && (Ch != '-') && (Ch != '+') &&
1205  (Ch != '/') && ((Ch < '0') || (Ch > '9')) && ((Ch < 'A') || (Ch > 'Z')) && ((Ch < 'a') || (Ch > 'z')))
1206  {
1207  Screen->Cursor = TCursor(-2); // Arrow
1208  ShowMessage(
1209  "Location name contains one or more invalid characters, must be alphanumeric, brackets, space, full stop, colon, inverted comma, '-', '+', '/' or '&&'");
1211  SetLevel1Mode(52);
1213  SetLevel2TrackMode(16);
1214  Utilities->CallLogPop(777);
1215  return;
1216  }
1217  }
1218  if(LocStr == "cdt") // this has Time:Command which could be confused with Time:Loc
1219  {
1220  Screen->Cursor = TCursor(-2); // Arrow
1221  ShowMessage("Location name cannot be 'cdt', this name would interfere with the timetable");
1223  SetLevel1Mode(53);
1225  SetLevel2TrackMode(17);
1226  Utilities->CallLogPop(778);
1227  return;
1228  }
1229  Track->EnterLocationName(2, LocStr, false);
1230  // need to check if the location already has a name, and if so erase it from the textvector
1231  int HPos, VPos;
1232  bool UseExistingPosition = false;
1233  if(ExistingName != "")
1234  {
1235  if(EraseLocationNameText(1, ExistingName, HPos, VPos))
1236  UseExistingPosition = true; // may be redundant at v1.1.0 due to name erase in EnterLocationName
1237  }
1238  AddLocationNameText(1, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1239  Screen->Cursor = TCursor(-2); // Arrow
1241  SetLevel1Mode(54);
1243  SetLevel2TrackMode(18);
1244  Utilities->CallLogPop(9);
1245  return;
1246  }
1247  }
1248  Screen->Cursor = TCursor(-2); // Arrow
1249  Utilities->CallLogPop(10);
1250  }
1251  catch(const Exception &e)
1252  {
1253  ErrorLog(5, e.Message);
1254  }
1255 }
1256 
1257 // ---------------------------------------------------------------------------
1258 void __fastcall TInterface::SetLengthsButtonClick(TObject *Sender)
1259 {
1260  try
1261  {
1262  TrainController->LogEvent("SetLengthsButtonClick");
1263  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SetLengthsButtonClick");
1264  SelectLengthsFlag = false;
1265  ConstructPrefDir->ExternalClearPrefDirAnd4MultiMap(); // added for extended distances
1267  SetLevel1Mode(55);
1269  SetLevel2TrackMode(19);
1270  Utilities->CallLogPop(1168);
1271  }
1272  catch(const Exception &e)
1273  {
1274  ErrorLog(127, e.Message);
1275  }
1276 }
1277 
1278 // ---------------------------------------------------------------------------
1279 void __fastcall TInterface::LengthOKButtonClick(TObject *Sender)
1280 {
1281  try
1282  {
1283  TrainController->LogEvent("LengthOKButtonClick," + DistanceBox->Text + "," + SpeedLimitBox->Text);
1284  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthOKButtonClick");
1285  int Dist = 0, SpeedLimit = 0;
1286  AnsiString DistanceStr = DistanceBox->Text;
1287  if(SelectLengthsFlag && (DistanceStr == ""))
1288  DistanceStr = "No change";
1289  AnsiString SpeedStr = SpeedLimitBox->Text;
1290  if(SelectLengthsFlag && (SpeedStr == ""))
1291  SpeedStr = "No change";
1292  if(SelectLengthsFlag)
1293  {
1294  if(DistanceStr == "No change")
1295  Dist = -1; // i.e.don't change
1296  if(SpeedStr == "No change")
1297  SpeedLimit = -1; // i.e.don't change
1298  }
1299  else
1300  {
1301  if(DistanceStr == AnsiString(OverallDistance))
1302  Dist = -1; // i.e.don't change
1303  if((SpeedStr == "Mixed") || (SpeedStr == AnsiString(OverallSpeedLimit)))
1304  SpeedLimit = -1; // i.e.don't change
1305  }
1306  if(((Dist != -1) && (DistanceStr.Length() > 6)) || ((SpeedLimit != -1) && (SpeedStr.Length() > 6)))
1307  {
1308  ShowMessage("One or more entries too long");
1309  Utilities->CallLogPop(11);
1310  return;
1311  }
1312  if((DistanceStr == "") || (SpeedStr == ""))
1313  {
1314  ShowMessage("One or more entries blank");
1315  Utilities->CallLogPop(12);
1316  return;
1317  }
1318  if(SelectLengthsFlag && (Dist != -1))
1319  {
1320  for(int x = 1; x <= DistanceStr.Length(); x++)
1321  {
1322  if((DistanceStr[x] < '0') || (DistanceStr[x] > '9'))
1323  {
1324  ShowMessage("Track length value must be a positive whole number, or blank for no change");
1325  Utilities->CallLogPop(1415);
1326  return;
1327  }
1328  }
1329  }
1330  if(!SelectLengthsFlag)
1331  {
1332  for(int x = 1; x <= DistanceStr.Length(); x++)
1333  {
1334  if((DistanceStr[x] < '0') || (DistanceStr[x] > '9'))
1335  {
1336  ShowMessage("Distance must be a positive whole number");
1337  Utilities->CallLogPop(13);
1338  return;
1339  }
1340  }
1341  }
1342  if(SelectLengthsFlag && (SpeedLimit != -1))
1343  {
1344  for(int x = 1; x <= SpeedStr.Length(); x++)
1345  {
1346  if((SpeedStr[x] < '0') || (SpeedStr[x] > '9'))
1347  {
1348  ShowMessage("Speed limit must be a positive whole number, or blank for no change");
1349  Utilities->CallLogPop(1416);
1350  return;
1351  }
1352  }
1353  }
1354  if(!SelectLengthsFlag && (SpeedStr != "Mixed"))
1355  {
1356  for(int x = 1; x <= SpeedStr.Length(); x++)
1357  {
1358  if((SpeedStr[x] < '0') || (SpeedStr[x] > '9'))
1359  {
1360  ShowMessage("Speed limit must be a positive whole number, or 'Mixed'");
1361  Utilities->CallLogPop(14);
1362  return;
1363  }
1364  }
1365  }
1366  if(Dist != -1)
1367  Dist = DistanceStr.ToInt();
1368  if(SpeedLimit != -1)
1369  SpeedLimit = SpeedStr.ToInt();
1370 /* don't need this with new condition below
1371  if(SelectLengthsFlag && (Dist != -1) && (Dist < 20))
1372  {
1373  ShowMessage("Track length value must be a minimum of 20m, setting to 20m");
1374  Dist = 20;
1375  }
1376 */
1377  if(((Dist != -1) && (Dist < 20)) || ((SpeedLimit != -1) && (SpeedLimit < 10)) || ((SpeedLimit != -1) && (SpeedLimit > TTrain::MaximumSpeedLimit)))
1378  // new limiting values for v0.6 (used only to fail at either value 0); added TTrain::MaxSpeedLimit at v2.1.0
1379  {
1380  ShowMessage("Lengths must be 20m or more, and speeds must be between 10km/h and 400km/h"); // changed at v2.1.0 to limit max speed
1381  Utilities->CallLogPop(15);
1382  return;
1383  }
1384  DistanceBox->Text = "";
1385  SpeedLimitBox->Text = "";
1386  if(SelectLengthsFlag)
1387  {
1388  int LowSelectHLoc = SelectBitmapHLoc;
1389  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
1390  int LowSelectVLoc = SelectBitmapVLoc;
1391  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
1392  bool FoundFlag;
1393  bool NamedLocPresent = false;
1394  if((Dist != -1) && (Dist != DefaultTrackLength))
1395  {
1396  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1397  {
1398  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1399  {
1401  NamedLocPresent = true;
1402  }
1403  }
1404  }
1405  if(NamedLocPresent && (Dist < 50)) // changed in v2.4.0
1406  {
1407  ShowMessage("Note: Named location elements are quite short. If they are too short the simulation might depart too far from reality.");
1408  }
1409 
1410  if(NamedLocPresent && (Dist > 200)) // changed in v2.4.0
1411  {
1412  ShowMessage("Note: Named location elements are quite long. If they are too long the simulation might depart too far from reality.");
1413  }
1414 
1415  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1416  {
1417  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1418  {
1419  int VecPos = Track->GetVectorPositionFromTrackMap(34, x, y, FoundFlag);
1420  if(FoundFlag)
1421  {
1422  if(Dist > -1) // && !(Track->IsPlatformOrNamedNonStationLocationPresent(7, x, y)))
1423  {
1424  Track->TrackElementAt(692, VecPos).Length01 = Dist;
1425  if(Track->TrackElementAt(693, VecPos).Length23 != -1)
1426  {
1427  Track->TrackElementAt(694, VecPos).Length23 = Dist;
1428  }
1429  }
1430  if(SpeedLimit > -1)
1431  {
1432  Track->TrackElementAt(695, VecPos).SpeedLimit01 = SpeedLimit;
1433  if(Track->TrackElementAt(696, VecPos).SpeedLimit23 != -1)
1434  {
1435  Track->TrackElementAt(697, VecPos).SpeedLimit23 = SpeedLimit;
1436  }
1437  }
1438  }
1439  }
1440  }
1441  TrackLengthPanel->Visible = false;
1442  SelectLengthsFlag = false; // go back to normal distance setting mode
1443  }
1444  else
1445  {
1446  SetTrackLengths(1, Dist, SpeedLimit);
1447  }
1449  SetLevel1Mode(57);
1451  SetLevel2TrackMode(21);
1452  Utilities->CallLogPop(16);
1453  }
1454  catch(const Exception &e)
1455  {
1456  ErrorLog(6, e.Message);
1457  }
1458 }
1459 
1460 // ---------------------------------------------------------------------------
1461 void __fastcall TInterface::LengthCancelButtonClick(TObject *Sender)
1462 {
1463  try
1464  {
1465  TrainController->LogEvent("LengthCancelButtonClick");
1466  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthCancelButtonClick");
1467  DistanceBox->Text = "";
1468  SpeedLimitBox->Text = "";
1469  TrackLengthPanel->Visible = false;
1470  SelectLengthsFlag = false; // go back to normal distance setting mode
1472  SetLevel1Mode(59);
1474  SetLevel2TrackMode(23);
1475  Utilities->CallLogPop(1169);
1476  }
1477  catch(const Exception &e)
1478  {
1479  ErrorLog(128, e.Message);
1480  }
1481 }
1482 
1483 // ---------------------------------------------------------------------------
1484 void __fastcall TInterface::ResetDefaultLengthButtonClick(TObject *Sender)
1485 {
1486  try
1487  {
1488  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ResetDefaultLengthButtonClick");
1489  TMsgDlgButtons Buttons;
1490  Buttons << mbYes << mbNo;
1491  if(MessageDlg("This will reset the selected elements to default lengths & speed limits. Proceed?", mtWarning, Buttons, 0) == mrNo)
1492  {
1493  // leave all as was before
1494  Utilities->CallLogPop(17);
1495  return;
1496  }
1497  else
1498  {
1499  TrainController->LogEvent("Accepted ResetDefaultLengthButtonClick");
1500  DistanceBox->Text = "";
1501  SpeedLimitBox->Text = "";
1502  if(SelectLengthsFlag)
1503  {
1504  int LowSelectHLoc = SelectBitmapHLoc;
1505  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
1506  int LowSelectVLoc = SelectBitmapVLoc;
1507  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
1508  bool FoundFlag;
1509  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1510  {
1511  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1512  {
1513  int VecPos = Track->GetVectorPositionFromTrackMap(35, x, y, FoundFlag);
1514  if(FoundFlag)
1515  {
1517  if(Track->TrackElementAt(699, VecPos).Length23 != -1)
1518  {
1520  }
1522  if(Track->TrackElementAt(702, VecPos).SpeedLimit23 != -1)
1523  {
1525  }
1526  }
1527  }
1528  }
1529  TrackLengthPanel->Visible = false;
1530 // ClearandRebuildRailway(47); don't need this
1531  SelectLengthsFlag = false; // go back to normal distance setting mode
1532  }
1533  else
1534  {
1535  TrackLengthPanel->Visible = false;
1536  bool FoundFlag;
1537  if(ConstructPrefDir->PrefDirSize() == 0)
1538  {
1539  Utilities->CallLogPop(1120);
1540  return;
1541  }
1542  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
1543  {
1544  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(169, x);
1545  TTrackElement & TrackElement = Track->TrackElementAt(37, Track->GetVectorPositionFromTrackMap(40, PrefDirElement.HLoc, PrefDirElement.VLoc,
1546  FoundFlag));
1547  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover) || (TrackElement.TrackType == Bridge))
1548  // only set the relevant track to default length & speed limit
1549  {
1550  if((PrefDirElement.GetELinkPos() < 2) && (PrefDirElement.GetXLinkPos() < 2)) // could be one of each for points
1551  {
1552  TrackElement.Length01 = DefaultTrackLength;
1553  TrackElement.SpeedLimit01 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1554  }
1555  else
1556  {
1557  TrackElement.Length23 = DefaultTrackLength;
1558  TrackElement.SpeedLimit23 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1559  }
1560  }
1561  else // any other 1 track element, including platforms being present
1562  {
1563  if((PrefDirElement.GetELinkPos() > 1) && (PrefDirElement.GetXLinkPos() > 1))
1564  {
1565  throw Exception("Error, XLinkPos > 1 in SetOneDefaultTrackLength at " + AnsiString(TrackElement.HLoc) + " & " +
1566  AnsiString(TrackElement.VLoc));
1567  }
1568  TrackElement.Length01 = DefaultTrackLength;
1569  TrackElement.SpeedLimit01 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1570  TrackElement.Length23 = -1;
1571  TrackElement.SpeedLimit23 = -1;
1572  }
1573  }
1574  }
1576  SetLevel1Mode(61);
1578  SetLevel2TrackMode(25);
1579  }
1580  Utilities->CallLogPop(18);
1581  }
1582  catch(const Exception &e)
1583  {
1584  ErrorLog(7, e.Message);
1585  }
1586 }
1587 
1588 // ---------------------------------------------------------------------------
1589 void __fastcall TInterface::RestoreAllDefaultLengthsButtonClick(TObject *Sender)
1590 {
1591  try
1592  {
1593  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RestoreAllDefaultLengthsButtonClick");
1594  TMsgDlgButtons Buttons;
1595  Buttons << mbYes << mbNo;
1596  if(MessageDlg("This will reset ALL track elements to default lengths & speed limits. Proceed?", mtWarning, Buttons, 0) == mrNo)
1597  {
1598  // leave all as was before
1599  Utilities->CallLogPop(19);
1600  return;
1601  }
1602  else
1603  {
1605  }
1606  TrainController->LogEvent("Accepted RestoreAllDefaultLengthsButtonClick");
1607  DistanceBox->Text = "";
1608  SpeedLimitBox->Text = "";
1609  TrackLengthPanel->Visible = false;
1610  SelectLengthsFlag = false; // go back to normal distance setting mode
1612  SetLevel1Mode(63);
1614  SetLevel2TrackMode(27);
1615  Utilities->CallLogPop(20);
1616  }
1617  catch(const Exception &e)
1618  {
1619  ErrorLog(8, e.Message);
1620  }
1621 }
1622 
1623 // ---------------------------------------------------------------------------
1624 void __fastcall TInterface::ExitTrackButtonClick(TObject *Sender)
1625 {
1626  try
1627  {
1628  TrainController->LogEvent("ExitTrackButtonClick");
1629  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitTrackButtonClick");
1630  if(Level2TrackMode == CutMoving)
1631  {
1632  Level2TrackMode = Pasting; // to paste the selection
1633  SetLevel2TrackMode(53);
1634  }
1635  DevelopmentPanel->Visible = false; // development use only
1636  ScreenGridFlag = false;
1637  SelectionValid = false;
1638  Track->SelectGraphicVector.clear();
1639  // delete all unwanted TPictures in UserGraphicMap
1640  if(!Track->UserGraphicMap.empty()) // if empty skip it
1641  {
1642  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1643  do
1644  {
1645  bool GraphicFoundInVector = false;
1646  for(TTrack::TUserGraphicVector::iterator UGVIt = Track->UserGraphicVector.begin(); UGVIt < Track->UserGraphicVector.end(); UGVIt++)
1647  {
1648  if(UGMIt->first == UGVIt->FileName)
1649  {
1650  GraphicFoundInVector = true;
1651  break;
1652  }
1653  }
1654  if(!GraphicFoundInVector)
1655  {
1656  delete UGMIt->second;
1657  Track->UserGraphicMap.erase(UGMIt);
1658  UGMIt = Track->UserGraphicMap.begin(); // reset the iterator because erasing an element it points to invalidates it & if use it after then
1659  // behaviour is undefined, the iteration will end eventually because the map has got shorter after an erase
1660  }
1661  else
1662  {
1663  UGMIt++;
1664  }
1665  }
1666  while(UGMIt != Track->UserGraphicMap.end());
1667  }
1668  Level1Mode = BaseMode;
1669  SetLevel1Mode(2);
1670  Utilities->CallLogPop(1170);
1671  }
1672  catch(const Exception &e)
1673  {
1674  ErrorLog(129, e.Message);
1675  }
1676 }
1677 
1678 // ---------------------------------------------------------------------------
1679 void __fastcall TInterface::TextOrUserGraphicGridButtonClick(TObject *Sender)
1680 {
1681  try
1682  {
1683  TrainController->LogEvent("TextOrUserGraphicGridButtonClick," + AnsiString(TextOrUserGraphicGridVal));
1684  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TextOrUserGraphicGridButtonClick");
1685  if(TextOrUserGraphicGridVal == 1)
1686  {
1688  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision2");
1689  }
1690  else if(TextOrUserGraphicGridVal == 2)
1691  {
1693  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision4");
1694  }
1695  else if(TextOrUserGraphicGridVal == 4)
1696  {
1698  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision8");
1699  }
1700  else if(TextOrUserGraphicGridVal == 8)
1701  {
1703  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision16");
1704  }
1705  else
1706  {
1708  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
1709  }
1710  Utilities->CallLogPop(1171);
1711  }
1712  catch(const Exception &e)
1713  {
1714  ErrorLog(130, e.Message);
1715  }
1716 }
1717 
1718 // ---------------------------------------------------------------------------
1719 void __fastcall TInterface::SigAspectButtonClick(TObject *Sender)
1720 {
1721  try
1722  {
1723  TrainController->LogEvent("SigAspectButtonClick," + AnsiString(Track->SignalAspectBuildMode));
1724  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigAspectButtonClick");
1726  {
1728  SigAspectButton->Glyph->LoadFromResourceName(0, "ThreeAspect");
1729  }
1731  {
1733  SigAspectButton->Glyph->LoadFromResourceName(0, "TwoAspect");
1734  }
1736  {
1738  SigAspectButton->Glyph->LoadFromResourceName(0, "GroundSig");
1739 // set all signal glyphs to ground signals
1741  }
1742  else
1743  {
1745  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect");
1746 // set all signal glyphs to normal signals
1748  }
1749  Utilities->CallLogPop(1869);
1750  }
1751  catch(const Exception &e)
1752  {
1753  ErrorLog(180, e.Message);
1754  }
1755 }
1756 
1757 // ---------------------------------------------------------------------------
1758 void __fastcall TInterface::FontButtonClick(TObject *Sender)
1759 {
1760  try
1761  {
1762  TrainController->LogEvent("FontButtonClick");
1763  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FontButtonClick");
1764  FontDialog->Font = Display->GetFont();
1765  FontDialog->Execute();
1766  if(FontDialog->Font->Color == clB5G5R5)
1767  FontDialog->Font->Color = clB0G0R0; // don't store white in font, will display black as white on
1768  // dark backgrounds
1769  Display->SetFont(FontDialog->Font);
1770  if(TextBox->Visible)
1771  TextBox->SetFocus();
1772  else if(LocationNameTextBox->Visible)
1773  LocationNameTextBox->SetFocus();
1774  Utilities->CallLogPop(1172);
1775  }
1776  catch(const Exception &e)
1777  {
1778  ErrorLog(131, e.Message);
1779  }
1780 }
1781 
1782 // ---------------------------------------------------------------------------
1783 
1784 void __fastcall TInterface::ScreenGridButtonClick(TObject *Sender)
1785 {
1786  try
1787  {
1788  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenGridButtonClick");
1789  if(ScreenGridFlag)
1790  {
1791  TrainController->LogEvent("ScreenGridButtonClick + ScreenGrid off");
1792  ScreenGridFlag = false;
1793  }
1794  else
1795  {
1796  TrainController->LogEvent("ScreenGridButtonClick + ScreenGrid on");
1797  ScreenGridFlag = true;
1798  }
1800  Utilities->CallLogPop(89);
1801  }
1802  catch(const Exception &e)
1803  {
1804  ErrorLog(33, e.Message);
1805  }
1806 }
1807 
1808 // ---------------------------------------------------------------------------
1809 // PrefDir Interface
1810 // ---------------------------------------------------------------------------
1811 void __fastcall TInterface::PlanPrefDirsMenuItemClick(TObject *Sender) // Mode Menu Item
1812 {
1813  try
1814  {
1815  TrainController->LogEvent("PlanPrefDirsMenuItemClick");
1816  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PlanPrefDirsMenuItemClick");
1818  SetLevel1Mode(3);
1819  Utilities->CallLogPop(1173);
1820  }
1821  catch(const Exception &e)
1822  {
1823  ErrorLog(132, e.Message);
1824  }
1825 }
1826 
1827 // ---------------------------------------------------------------------------
1828 void __fastcall TInterface::AddPrefDirButtonClick(TObject *Sender)
1829 {
1830  try
1831  {
1832  TrainController->LogEvent("AddPrefDirButtonClick");
1833  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddPrefDirButtonClick");
1834  if(ConstructPrefDir->PrefDirSize() == 0)
1835  {
1836  ShowMessage("No preferred direction selection");
1837  Utilities->CallLogPop(22);
1838  return;
1839  }
1840  Screen->Cursor = TCursor(-11); // Hourglass;
1844  SetLevel1Mode(4);
1845  Screen->Cursor = TCursor(-2); // Arrow
1846  Utilities->CallLogPop(23);
1847  }
1848  catch(const Exception &e)
1849  {
1850  ErrorLog(10, e.Message);
1851  }
1852 }
1853 
1854 // ---------------------------------------------------------------------------
1855 void __fastcall TInterface::DeleteAllPrefDirButtonClick(TObject *Sender)
1856 {
1857  try
1858  {
1859  TrainController->LogEvent("DeleteAllPrefDirButtonClick");
1860  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteAllPrefDirButtonClick");
1861  TMsgDlgButtons Buttons;
1862  Buttons << mbYes << mbNo;
1863  if(MessageDlg("Do you really want to clear all preferred directions?", mtWarning, Buttons, 0) == mrNo)
1864  {
1865  Utilities->CallLogPop(24);
1866  return;
1867  }
1868  // leave all as was before pressed DeleteAllPrefDirButton
1869  else
1870  {
1875  SetLevel1Mode(5);
1876  }
1877  Utilities->CallLogPop(25);
1878  }
1879  catch(const Exception &e)
1880  {
1881  ErrorLog(11, e.Message);
1882  }
1883 }
1884 // ---------------------------------------------------------------------------
1885 
1886 void __fastcall TInterface::DeleteOnePrefDirButtonClick(TObject *Sender)
1887 {
1888  try
1889  {
1890  TrainController->LogEvent("DeleteOnePrefDirButtonClick");
1891  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteOnePrefDirButtonClick");
1892  ResetChangedFileDataAndCaption(18, false);
1893 // RlyFile = false; - don't alter this just for PrefDir changes
1894  Screen->Cursor = TCursor(-11); // Hourglass;
1895  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
1896  {
1899  }
1902  SetLevel1Mode(81); // all PrefDir truncated
1903  Screen->Cursor = TCursor(-2); // Arrow
1904  Utilities->CallLogPop(1591);
1905  }
1906  catch(const Exception &e)
1907  {
1908  ErrorLog(46, e.Message);
1909  }
1910 }
1911 
1912 // ---------------------------------------------------------------------------
1913 
1914 void __fastcall TInterface::ExitPrefDirButtonClick(TObject *Sender)
1915 {
1916  try
1917  {
1918  TrainController->LogEvent("ExitPrefDirButtonClick");
1919  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitPrefDirButtonClick");
1920  Level1Mode = BaseMode;
1921  SetLevel1Mode(6);
1922  Utilities->CallLogPop(1554);
1923  }
1924  catch(const Exception &e)
1925  {
1926  ErrorLog(133, e.Message);
1927  }
1928 }
1929 
1930 // ---------------------------------------------------------------------------
1931 // Operate Railway Interface
1932 // ---------------------------------------------------------------------------
1933 void __fastcall TInterface::OperateRailwayMenuItemClick(TObject *Sender) // Mode Menu Item
1934 {
1935  try
1936  {
1937  TrainController->LogEvent("OperateRailwayMenuItemClick");
1938  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperateRailwayMenuItemClick");
1939  TTrain::NextTrainID = 0; // reset to 0 whenever enter operating mode
1940  AllRoutes->NextRouteID = 0; // reset to 0 whenever enter operating mode
1941  Level1Mode = OperMode;
1942  SetLevel1Mode(7);
1943  Utilities->CallLogPop(26);
1944  }
1945  catch(const Exception &e)
1946  {
1947  ErrorLog(12, e.Message);
1948  }
1949 }
1950 
1951 // ---------------------------------------------------------------------------
1952 void __fastcall TInterface::OperateButtonClick(TObject *Sender)
1953 {
1954  try
1955  {
1956  TrainController->LogEvent("StartOperationButtonClick");
1957  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperateButtonClick");
1959  {
1961  SetLevel2OperMode(0);
1962  }
1963  else
1964  {
1966  SetLevel2OperMode(1);
1967  }
1968  Utilities->CallLogPop(1175);
1969  }
1970  catch(const Exception &e)
1971  {
1972  ErrorLog(37, e.Message);
1973  }
1974 }
1975 
1976 // ---------------------------------------------------------------------------
1977 void __fastcall TInterface::AutoSigsButtonClick(TObject *Sender)
1978  // must have PrefDirs to be available
1979 {
1980  try
1981  {
1982  TrainController->LogEvent("AutoSigsButtonClick");
1983  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AutoSigsButtonClick");
1984  AutoSigsFlag = true;
1985  PreferredRoute = true;
1986  ConsecSignalsRoute = true;
1987 
1988  AutoSigsButton->Enabled = false;
1989  SigPrefButton->Enabled = true;
1990  UnrestrictedButton->Enabled = true;
1991 
1992  InfoPanel->Visible = true;
1993  if(Level2OperMode == PreStart)
1994  InfoPanel->Caption = "PRE-START: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
1995  else
1996  InfoPanel->Caption = "OPERATING: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
1997  InfoCaptionStore = InfoPanel->Caption;
1998  AutoRouteStartMarker->PlotOriginal(1, Display); // if overlay not plotted will ignore
1999  SigRouteStartMarker->PlotOriginal(2, Display); // if overlay not plotted will ignore
2000  NonSigRouteStartMarker->PlotOriginal(3, Display); // if overlay not plotted will ignore
2002  Utilities->CallLogPop(28);
2003  }
2004  catch(const Exception &e)
2005  {
2006  ErrorLog(14, e.Message);
2007  }
2008 }
2009 
2010 // ---------------------------------------------------------------------------
2011 void __fastcall TInterface::SigPrefButtonClick(TObject *Sender)
2012  // must have PrefDirs to be available
2013 {
2014  try
2015  {
2016  TrainController->LogEvent("SigPrefButtonClick");
2017  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigPrefButtonClick");
2018  AutoSigsFlag = false;
2019  PreferredRoute = true;
2020  ConsecSignalsRoute = true;
2021 
2022  AutoSigsButton->Enabled = true;
2023  SigPrefButton->Enabled = false;
2024  UnrestrictedButton->Enabled = true;
2025 
2026  InfoPanel->Visible = true;
2027  if(Level2OperMode == PreStart)
2028  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
2029  else
2030  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
2031  InfoCaptionStore = InfoPanel->Caption;
2032  AutoRouteStartMarker->PlotOriginal(4, Display); // if overlay not plotted will ignore
2033  SigRouteStartMarker->PlotOriginal(5, Display); // if overlay not plotted will ignore
2034  NonSigRouteStartMarker->PlotOriginal(6, Display); // if overlay not plotted will ignore
2036  Utilities->CallLogPop(29);
2037  }
2038  catch(const Exception &e)
2039  {
2040  ErrorLog(15, e.Message);
2041  }
2042 }
2043 
2044 // ---------------------------------------------------------------------------
2045 void __fastcall TInterface::UnrestrictedButtonClick(TObject *Sender)
2046 {
2047  try
2048  {
2049  TrainController->LogEvent("NoSigNonPrefButtonClick");
2050  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NoSigNonPrefButtonClick");
2051  AutoSigsFlag = false;
2052  PreferredRoute = false;
2053  ConsecSignalsRoute = false;
2054  if(EveryPrefDir->PrefDirSize() > 0)
2055  {
2056  AutoSigsButton->Enabled = true;
2057  SigPrefButton->Enabled = true;
2058  UnrestrictedButton->Enabled = false;
2059  }
2060  else
2061  {
2062  AutoSigsButton->Enabled = false;
2063  SigPrefButton->Enabled = false;
2064  UnrestrictedButton->Enabled = false;
2065  }
2066  InfoPanel->Visible = true;
2067  if(Level2OperMode == PreStart)
2068  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
2069  else
2070  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
2071  InfoCaptionStore = InfoPanel->Caption;
2072  AutoRouteStartMarker->PlotOriginal(7, Display); // if overlay not plotted will ignore
2073  SigRouteStartMarker->PlotOriginal(8, Display); // if overlay not plotted will ignore
2074  NonSigRouteStartMarker->PlotOriginal(9, Display); // if overlay not plotted will ignore
2076  Utilities->CallLogPop(30);
2077  }
2078  catch(const Exception &e)
2079  {
2080  ErrorLog(16, e.Message);
2081  }
2082 }
2083 
2084 // ---------------------------------------------------------------------------
2085 void __fastcall TInterface::RouteCancelButtonClick(TObject *Sender)
2086 {
2087  try
2088  {
2089  TrainController->LogEvent("RouteCancelButtonClick");
2090  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RouteCancelButtonClick");
2091  RouteCancelFlag = true;
2092  InfoPanel->Visible = true;
2093  InfoPanel->Caption = "ROUTE CANCELLING: Right click on truncate element, first element to cancel (anywhere else to skip)";
2094  RouteCancelButton->Enabled = false;
2095  AutoRouteStartMarker->PlotOriginal(32, Display); // if overlay not plotted will ignore
2096  SigRouteStartMarker->PlotOriginal(33, Display); // if overlay not plotted will ignore
2097  NonSigRouteStartMarker->PlotOriginal(34, Display); // if overlay not plotted will ignore
2098  Utilities->CallLogPop(1176);
2099  }
2100  catch(const Exception &e)
2101  {
2102  ErrorLog(35, e.Message);
2103  }
2104 }
2105 
2106 // ---------------------------------------------------------------------------
2107 void __fastcall TInterface::PerformanceLogButtonClick(TObject *Sender)
2108 {
2109  try
2110  {
2111  TrainController->LogEvent("PerformanceLogButtonClick");
2112  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformanceLogButtonClick");
2114  {
2115  ShowPerformancePanel = true;
2116  PerformancePanel->Visible = true;
2117  PerformanceLogButton->Glyph->LoadFromResourceName(0, "HideLog");
2118  }
2119  else
2120  {
2121  ShowPerformancePanel = false;
2122  PerformancePanel->Visible = false;
2123  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
2124  }
2125  Utilities->CallLogPop(1177);
2126  }
2127  catch(const Exception &e)
2128  {
2129  ErrorLog(36, e.Message);
2130  }
2131 }
2132 // ---------------------------------------------------------------------------
2133 
2134 void __fastcall TInterface::ExitOperationButtonClick(TObject *Sender)
2135 {
2136  try
2137  {
2138  TrainController->LogEvent("ExitOperationButtonClick");
2139  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitOperationButtonClick");
2140 
2141  UnicodeString MessageStr = "Please note that the session will be lost if it hasn't been saved. Do you still wish to exit?";
2142  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2144  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
2145  TrainController->BaseTime = TDateTime::CurrentDateTime();
2147  if(button == IDNO)
2148  {
2149  Utilities->CallLogPop(751);
2150  return;
2151  }
2152  Track->ResetSignals(1);
2153  Track->ResetPoints(1);
2154  TrainController->SendPerformanceSummary(0, Utilities->PerformanceFile); // must come before trains finished becuase examines the train vectors
2155  Utilities->PerformanceFile.close();
2158  RouteMode = None;
2159  PreferredRoute = true;
2160  ConsecSignalsRoute = true;
2162  ShowPerformancePanel = false;
2163  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
2164  ShowOperatorActionPanel = false; // new at v2.2.0
2165  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel"); // new v2.2.0
2166  PerformanceLogBox->Lines->Clear();
2167  PerformancePanel->Visible = false;
2168  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
2169  PerformancePanel->Left = MainScreen->Left;
2170 // TipButton->Glyph->LoadFromResourceName(0, "ShowLog"); //'Trains in play' new at v2.2.0
2171  OAListBox->Clear();
2172  OperatorActionPanel->Visible = false;
2173  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height;
2174  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width; ;
2176  AllRoutes->LockedRouteVector.clear();
2177  Level1Mode = BaseMode;
2178  SetLevel1Mode(8); // calls Clearand...
2179  Utilities->CallLogPop(1555);
2180  }
2181  catch(const Exception &e)
2182  {
2183  ErrorLog(13, e.Message);
2184  }
2185 }
2186 
2187 // ---------------------------------------------------------------------------
2188 // Menu Interface (for items not already covered above)
2189 // ---------------------------------------------------------------------------
2190 void __fastcall TInterface::LoadRailwayMenuItemClick(TObject *Sender)
2191 {
2192  try
2193  {
2194  TrainController->LogEvent("LoadRailwayMenuItemClick");
2195  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LoadRailwayMenuItemClick");
2196  if(!ClearEverything(1))
2197  {
2198  Utilities->CallLogPop(1139);
2199  return;
2200  }
2201  // LoadRailwayDialog->Filter = "Development file (*.dev)|*.dev|Railway file (*.rly)|*.rly"; //as was
2202  // changed at v2.0.0 (Embarcadero change) to show all files together
2203  LoadRailwayDialog->Filter = "Railway files (*.rly or *.dev)|*.rly; *.dev";
2204  if(LoadRailwayDialog->Execute())
2205  {
2206  TrainController->LogEvent("LoadRailway " + AnsiString(LoadRailwayDialog->FileName));
2207  LoadRailway(0, AnsiString(LoadRailwayDialog->FileName));
2208  }
2209  // else ShowMessage("Load Aborted"); drop this
2210  // Display->Update(); //display updated in ClearandRebuildRailway
2211  Track->CalcHLocMinEtc(9);
2212  Level1Mode = BaseMode;
2215  SetLevel1Mode(11); // calls Clearand... to plot the new railway
2216  Utilities->CallLogPop(31);
2217  }
2218  catch(const Exception &e)
2219  {
2220  ErrorLog(17, e.Message);
2221  }
2222 }
2223 // ---------------------------------------------------------------------------
2224 
2225 void TInterface::LoadRailway(int Caller, AnsiString LoadFileName)
2226 { // display of the loaded railway covered in the calling routine
2227  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRailway," + LoadFileName);
2228  if(FileIntegrityCheck(0, LoadFileName.c_str()))
2229  {
2230  Screen->Cursor = TCursor(-11); // Hourglass;
2231  std::ifstream VecFile(LoadFileName.c_str());
2232  if(!(VecFile.fail()))
2233  {
2234  AnsiString TempString = Utilities->LoadFileString(VecFile); // version number
2235  int TempOffsetHHome = Utilities->LoadFileInt(VecFile);
2236  int TempOffsetVHome = Utilities->LoadFileInt(VecFile);
2237  bool GraphicsFollow = false;
2238  // can't load DisplayOffsetH & VHome until after LoadTrack as that calls TrackClear & zeroes them
2239 // load track elements
2240  Track->LoadTrack(1, VecFile, GraphicsFollow);
2241 // load text elements
2242  TextHandler->LoadText(0, VecFile);
2243 // load PrefDir elements
2244  EveryPrefDir->LoadPrefDir(0, VecFile);
2245  if(GraphicsFollow)
2246  {
2247 // load user graphics
2248  Track->LoadGraphics(0, VecFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME); // include path to Graphics folder
2249  }
2250  EveryPrefDir->CheckPrefDirAgainstTrackVector(0); // clears PrefDir if any discrepancies found
2251  VecFile.close();
2252  Display->DisplayOffsetHHome = TempOffsetHHome;
2253  Display->DisplayOffsetVHome = TempOffsetVHome;
2255 
2256  TFont *TempFont = new TFont; // if try to alter MainScreen->Canvas->Font directly it won't change the style for some reason
2257  TempFont->Style.Clear();
2258  TempFont->Name = "MS Sans Serif"; // reset font, else stays set to last displayed text font
2259  TempFont->Size = 10;
2260  TempFont->Color = clB0G0R0;
2261  TempFont->Charset = (TFontCharset)(0);
2262  MainScreen->Canvas->Font->Assign(TempFont);
2263  delete TempFont;
2264 
2265 // calculate starting zoomed out offset values - same as when zoom out button clicked
2266  int OVOffH_NVCentre = Display->DisplayOffsetH - (1.5 * Utilities->ScreenElementWidth);
2267 // start zoomout centre at DisplayOffsetH + 30 - zoomout width/2 = -(1.5 * 60)
2268  int LeftExcess = OVOffH_NVCentre - Track->GetHLocMin();
2269  int RightExcess = Track->GetHLocMax() - OVOffH_NVCentre - ((4 * Utilities->ScreenElementWidth) - 1);
2270  if((LeftExcess > 0) && (RightExcess > 0))
2271  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre;
2272  else if((LeftExcess > 0) && (RightExcess <= 0))
2273  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre + ((RightExcess) / (Utilities->ScreenElementWidth / 2)) *
2274  (Utilities->ScreenElementWidth / 2); // normalise to nearest half screen
2275  else if((LeftExcess <= 0) && (RightExcess > 0))
2276  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre - ((LeftExcess) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2);
2277  else
2278  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre; // no excess at either side, so display in centre
2279 
2280  int OVOffV_NVCentre = Display->DisplayOffsetV - (1.5 * Utilities->ScreenElementHeight);
2281  int TopExcess = OVOffV_NVCentre - Track->GetVLocMin();
2282  int BotExcess = Track->GetVLocMax() - OVOffV_NVCentre - ((4 * Utilities->ScreenElementHeight) - 1);
2283  if((TopExcess > 0) && (BotExcess > 0))
2284  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre;
2285  else if((TopExcess > 0) && (BotExcess <= 0))
2286  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre + ((BotExcess) / (Utilities->ScreenElementHeight / 2)) *
2287  (Utilities->ScreenElementHeight / 2); // normalise to nearest half screen
2288  else if((TopExcess <= 0) && (BotExcess > 0))
2289  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre - ((TopExcess) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2);
2290  else
2291  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre; // no excess at either side, so display in centre
2292 // all above same as when zoom out button clicked
2293  Display->DisplayZoomOutOffsetVHome = Display->DisplayZoomOutOffsetV; // now set zoomed out 'home' values
2295 
2296  SavedFileName = AnsiString(LoadRailwayDialog->FileName); // includes the full PrefDir
2297  if(SavedFileName != "") // shouldn't be "" at this stage but leave in as a safeguard
2298  {
2299  char LastChar = SavedFileName[SavedFileName.Length()];
2300  if((LastChar == 'y') || (LastChar == 'Y'))
2301  {
2302  if(!(Track->IsReadyForOperation()))
2303  {
2304  ShowMessage("Railway not ready for operation so unable to load as a .rly file. Loading as a new railway under development");
2305  SavedFileName = "";
2306  RlyFile = false;
2307  RailwayTitle = "";
2308  TimetableTitle = "";
2309  SetCaption(5);
2310  Track->CalcHLocMinEtc(1);
2311  Screen->Cursor = TCursor(-2); // Arrow
2312  Level1Mode = BaseMode;
2313  SetLevel1Mode(9);
2314  Utilities->CallLogPop(1136);
2315  return;
2316  }
2317  else
2318  {
2319  RlyFile = true;
2320  }
2321  }
2322  else
2323  {
2324  RlyFile = false;
2325  }
2326  }
2327  else
2328  {
2329  RlyFile = false;
2330  }
2331  FileChangedFlag = false;
2332  for(int x = AnsiString(LoadRailwayDialog->FileName).Length(); x > 0; x--)
2333  {
2334  if(AnsiString(LoadRailwayDialog->FileName)[x] == '\\')
2335  {
2336  RailwayTitle = AnsiString(LoadRailwayDialog->FileName).SubString(x + 1, AnsiString(LoadRailwayDialog->FileName).Length() - x - 4);
2337  TimetableTitle = "";
2338  SetCaption(6);
2339  break;
2340  }
2341  }
2342  } // if(VecFile)
2343  else
2344  ShowMessage("File open failed prior to load");
2345  Screen->Cursor = TCursor(-2); // Arrow
2346  } // if(FileIntegrityCheck(LoadRailwayDialog->FileName.c_str()))
2347  else
2348  ShowMessage("File integrity check failed - unable to load");
2349  Utilities->CallLogPop(1774);
2350 }
2351 
2352 // ---------------------------------------------------------------------------
2353 
2354 void __fastcall TInterface::SaveMenuItemClick(TObject *Sender)
2355 {
2356 // save under existing name
2357 // no need to alter RlyFile for saving under existing name
2358 
2359  try
2360  {
2361  TrainController->LogEvent("SaveMenuItemClick, " + SavedFileName);
2362  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveMenuItemClick");
2363  Screen->Cursor = TCursor(-11); // Hourglass;
2364  std::ofstream VecFile(SavedFileName.c_str());
2365  if(!(VecFile.fail()))
2366  {
2370  // save track elements
2371  if(Track->UserGraphicVector.empty())
2372  {
2373  Track->SaveTrack(3, VecFile, false); // false for no graphics (**Active elements** saved as marker)
2374  }
2375  else
2376  {
2377  Track->SaveTrack(8, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
2378  }
2379  // save text elements
2380  TextHandler->SaveText(0, VecFile);
2381  // save PrefDir elements
2382  EveryPrefDir->SavePrefDirVector(0, VecFile);
2383  if(!Track->UserGraphicVector.empty())
2384  {
2385  // save user graphics
2386  Track->SaveUserGraphics(0, VecFile);
2387  }
2388  FileChangedFlag = false;
2389  VecFile.close();
2390  }
2391  else
2392  ShowMessage("File open failed prior to save");
2393  Screen->Cursor = TCursor(-2); // Arrow
2394  Level1Mode = BaseMode;
2395  SetLevel1Mode(12); // to disable the save option
2396  Utilities->CallLogPop(1178);
2397  }
2398  catch(const Exception &e)
2399  {
2400  ErrorLog(135, e.Message);
2401  }
2402 }
2403 
2404 // ---------------------------------------------------------------------------
2405 void __fastcall TInterface::SaveAsMenuItemClick(TObject *Sender)
2406 {
2407  try
2408  {
2409  TrainController->LogEvent("SaveAsMenuItemClick");
2410  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveAsMenuItemClick");
2411  SaveAsSubroutine(0);
2412  Utilities->CallLogPop(32);
2413  }
2414  catch(const Exception &e)
2415  {
2416  ErrorLog(18, e.Message);
2417  }
2418 }
2419 
2420 // ---------------------------------------------------------------------------
2421 
2422 void __fastcall TInterface::SaveImageNoGridMenuItemClick(TObject *Sender)
2423 { // need to stop clock in case invoke during operation
2424  try
2425  {
2426  TrainController->LogEvent("SaveImageNoGridMenuItemClick");
2427  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageNoGridMenuItemClick");
2428  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2429  {
2430  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2431  Utilities->CallLogPop(1695);
2432  return;
2433  }
2434  Screen->Cursor = TCursor(-11); // Hourglass;
2435  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2437  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2438  // format "16/06/2009 20:55:17"
2439  // avoid characters in filename:= / \ : * ? " < > |
2440  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2441  AnsiString ShortName = "";
2442  for(int x = ImageFileName.Length(); x > 0; x--)
2443  {
2444  if(ImageFileName[x] == '\\')
2445  {
2446  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2447  break;
2448  }
2449  }
2450  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2451  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2452  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2453 
2454  int HPosMin = Track->GetHLocMin() * 16;
2455  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2456  int VPosMin = Track->GetVLocMin() * 16;
2457  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2458  RailwayImage->Width = HPosMax - HPosMin;
2459  RailwayImage->Height = VPosMax - VPosMin;
2460 
2461  // need to check if there is any text that extends past HPosMax or below VPosMax
2462  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2463  if(!TextHandler->TextVector.empty())
2464  {
2465  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2466  {
2467  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2468  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2469  if(NewWidth > RailwayImage->Width)
2470  {
2471  RailwayImage->Width = NewWidth;
2472  }
2473  if(NewHeight > RailwayImage->Height)
2474  {
2475  RailwayImage->Height = NewHeight;
2476  }
2477  }
2478  }
2479 
2480  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2481  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2482  RailwayImage->Canvas->FillRect(Rect);
2483 
2484  // write graphics first so text & track overwrite
2485  Track->WriteGraphicsToImage(0, RailwayImage);
2486  // then write text so track overwrites
2487  TextHandler->WriteTextToImage(0, RailwayImage);
2488  Track->WriteTrackToImage(0, RailwayImage);
2489 
2490  RailwayImage->SaveToFile(ImageFileName);
2491  delete RailwayImage;
2492  TrainController->BaseTime = TDateTime::CurrentDateTime();
2494  Screen->Cursor = TCursor(-2); // Arrow
2495  Utilities->CallLogPop(1535);
2496  }
2497  catch(const Exception &e)
2498  {
2499  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2500  {
2501  Screen->Cursor = TCursor(-2); // Arrow;
2502  UnicodeString MessageStr = "Insufficient memory available to store this image";
2503  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2504  }
2505  else
2506  {
2507  ErrorLog(42, e.Message);
2508  }
2509  }
2510 }
2511 
2512 // ---------------------------------------------------------------------------
2513 
2514 void __fastcall TInterface::SaveImageAndGridMenuItemClick(TObject *Sender)
2515 { // need to stop clock in case invoke during operation
2516  try
2517  {
2518  TrainController->LogEvent("SaveImageAndGridMenuItemClick");
2519  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageAndGridMenuItemClick");
2520  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2521  {
2522  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2523  Utilities->CallLogPop(1696);
2524  return;
2525  }
2526  Screen->Cursor = TCursor(-11); // Hourglass;
2527  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2529  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2530  // format "16/06/2009 20:55:17"
2531  // avoid characters in filename:= / \ : * ? " < > |
2532  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2533  AnsiString ShortName = "";
2534  for(int x = ImageFileName.Length(); x > 0; x--)
2535  {
2536  if(ImageFileName[x] == '\\')
2537  {
2538  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2539  break;
2540  }
2541  }
2542  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2543  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2544  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2545  int HPosMin = Track->GetHLocMin() * 16;
2546  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2547  int VPosMin = Track->GetVLocMin() * 16;
2548  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2549  RailwayImage->Width = HPosMax - HPosMin;
2550  RailwayImage->Height = VPosMax - VPosMin;
2551 
2552  // need to check if there is any text that extends past HPosMax or below VPosMax
2553  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2554  if(!TextHandler->TextVector.empty())
2555  {
2556  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2557  {
2558  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2559  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2560  if(NewWidth > RailwayImage->Width)
2561  {
2562  RailwayImage->Width = NewWidth;
2563  }
2564  if(NewHeight > RailwayImage->Height)
2565  {
2566  RailwayImage->Height = NewHeight;
2567  }
2568  }
2569  }
2570 
2571  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2572  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2573  RailwayImage->Canvas->FillRect(Rect);
2574 
2575  // write the grid first so all else on top
2576  for(int x = 0; x < ((RailwayImage->Width) / 16); x++)
2577  {
2578  for(int y = 0; y < ((RailwayImage->Height) / 16); y++)
2579  {
2580  RailwayImage->Canvas->Draw((x * 16), (y * 16), RailGraphics->bmGrid); // graphic is black on white so no need to change
2581  }
2582  }
2583  // write graphics next so text & track overwrite
2584  Track->WriteGraphicsToImage(1, RailwayImage);
2585  // then write text so track overwrites
2586  TextHandler->WriteTextToImage(1, RailwayImage);
2587  Track->WriteTrackToImage(1, RailwayImage);
2588  RailwayImage->SaveToFile(ImageFileName);
2589  delete RailwayImage;
2590  TrainController->BaseTime = TDateTime::CurrentDateTime();
2592  Screen->Cursor = TCursor(-2); // Arrow
2593  Utilities->CallLogPop(1536);
2594  }
2595  catch(const Exception &e)
2596  {
2597  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2598  {
2599  Screen->Cursor = TCursor(-2); // Arrow;
2600  UnicodeString MessageStr = "Insufficient memory available to store this image";
2601  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2602  }
2603  else
2604  {
2605  ErrorLog(43, e.Message);
2606  }
2607  }
2608 }
2609 // ---------------------------------------------------------------------------
2610 
2611 void __fastcall TInterface::SaveImageAndPrefDirsMenuItemClick(TObject *Sender)
2612 { // need to stop clock in case invoke during operation
2613  try
2614  {
2615  TrainController->LogEvent("SaveImageAndPrefDirsMenuItemClick");
2616  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageAndPrefDirsMenuItemClick");
2617  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2618  {
2619  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2620  Utilities->CallLogPop(1697);
2621  return;
2622  }
2623  Screen->Cursor = TCursor(-11); // Hourglass;
2624  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2626  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2627  // format "16/06/2009 20:55:17"
2628  // avoid characters in filename:= / \ : * ? " < > |
2629  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2630  AnsiString ShortName = "";
2631  for(int x = ImageFileName.Length(); x > 0; x--)
2632  {
2633  if(ImageFileName[x] == '\\')
2634  {
2635  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2636  break;
2637  }
2638  }
2639  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2640  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2641  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2642  int HPosMin = Track->GetHLocMin() * 16;
2643  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2644  int VPosMin = Track->GetVLocMin() * 16;
2645  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2646  RailwayImage->Width = HPosMax - HPosMin;
2647  RailwayImage->Height = VPosMax - VPosMin;
2648 
2649  // need to check if there is any text that extends past HPosMax or below VPosMax
2650  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2651  if(!TextHandler->TextVector.empty())
2652  {
2653  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2654  {
2655  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2656  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2657  if(NewWidth > RailwayImage->Width)
2658  {
2659  RailwayImage->Width = NewWidth;
2660  }
2661  if(NewHeight > RailwayImage->Height)
2662  {
2663  RailwayImage->Height = NewHeight;
2664  }
2665  }
2666  }
2667 
2668  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2669  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2670  RailwayImage->Canvas->FillRect(Rect);
2671 
2672  // write graphics first so text & track overwrite
2673  Track->WriteGraphicsToImage(2, RailwayImage);
2674  // then write text so track overwrites
2675  TextHandler->WriteTextToImage(2, RailwayImage);
2676  Track->WriteTrackToImage(2, RailwayImage);
2677  EveryPrefDir->WritePrefDirToImage(0, RailwayImage);
2678  RailwayImage->SaveToFile(ImageFileName);
2679  delete RailwayImage;
2680  TrainController->BaseTime = TDateTime::CurrentDateTime();
2682  Screen->Cursor = TCursor(-2); // Arrow
2683  Utilities->CallLogPop(1566);
2684  }
2685  catch(const Exception &e)
2686  {
2687  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2688  {
2689  Screen->Cursor = TCursor(-2); // Arrow;
2690  UnicodeString MessageStr = "Insufficient memory available to store this image";
2691  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2692  }
2693  else
2694  {
2695  ErrorLog(45, e.Message);
2696  }
2697  }
2698 }
2699 // ---------------------------------------------------------------------------
2700 
2701 void __fastcall TInterface::SaveOperatingImageMenuItemClick(TObject *Sender)
2702 { // need to stop clock
2703  try
2704  {
2705  TrainController->LogEvent("SaveOperatingImageMenuItemClick");
2706  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveOperatingImageMenuItemClick");
2707  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2708  {
2709  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2710  Utilities->CallLogPop(1702);
2711  return;
2712  }
2713  Screen->Cursor = TCursor(-11); // Hourglass;
2714  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2716 
2717  AnsiString TimetableTimeStr = Utilities->Format96HHMMSS(TrainController->TTClockTime);
2718  TimetableTimeStr = TimetableTimeStr.SubString(1, 2) + '.' + TimetableTimeStr.SubString(4, 2) + '.' + TimetableTimeStr.SubString(7, 2);
2719  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2720  // format "16/06/2009 20:55:17"
2721  // avoid characters in filename:= / \ : * ? " < > |
2722  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
2723  "; " + TimetableTitle + ".bmp";
2724  AnsiString ShortName = "";
2725  for(int x = ImageFileName.Length(); x > 0; x--)
2726  {
2727  if(ImageFileName[x] == '\\')
2728  {
2729  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2730  break;
2731  }
2732  }
2733  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2734  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2735  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2736  int HPosMin = Track->GetHLocMin() * 16;
2737  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2738  int VPosMin = Track->GetVLocMin() * 16;
2739  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2740  RailwayImage->Width = HPosMax - HPosMin;
2741  RailwayImage->Height = VPosMax - VPosMin;
2742 
2743  // need to check if there is any text that extends past HPosMax or below VPosMax
2744  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2745  if(!TextHandler->TextVector.empty())
2746  {
2747  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2748  {
2749  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2750  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2751  if(NewWidth > RailwayImage->Width)
2752  {
2753  RailwayImage->Width = NewWidth;
2754  }
2755  if(NewHeight > RailwayImage->Height)
2756  {
2757  RailwayImage->Height = NewHeight;
2758  }
2759  }
2760  }
2761 
2762  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2763  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2764  RailwayImage->Canvas->FillRect(Rect);
2765 
2766  // write graphics first so text & track overwrite
2767  Track->WriteGraphicsToImage(3, RailwayImage);
2768  // then write text so track overwrites
2769  TextHandler->WriteTextToImage(3, RailwayImage);
2770  Track->WriteOperatingTrackToImage(0, RailwayImage); // need points with single fillets, signals with colours, gaps all connected
2771  AllRoutes->WriteAllRoutesToImage(0, RailwayImage);
2772 // add any locked route markers
2773  if(!AllRoutes->LockedRouteVector.empty())
2774  {
2775  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
2776  {
2777  TOneRoute Route = AllRoutes->GetFixedRouteAt(167, LRVIT->RouteNumber);
2778  int x = Route.PrefDirSize() - 1;
2779  bool BreakFlag = false;
2780  TPrefDirElement PrefDirElement = Route.GetFixedPrefDirElementAt(188, x);
2781  while(PrefDirElement.GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
2782  {
2783  RailwayImage->Canvas->Draw((PrefDirElement.HLoc - Track->GetHLocMin()) * 16, (PrefDirElement.VLoc - Track->GetVLocMin()) * 16,
2784  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
2785  if(!(AllRoutes->TrackIsInARoute(13, PrefDirElement.Conn[PrefDirElement.GetELinkPos()],
2786  PrefDirElement.ConnLinkPos[PrefDirElement.GetELinkPos()])))
2787  {
2788  BreakFlag = true;
2789  break; // train removed earlier element from route so stop here
2790  }
2791  x--;
2792  PrefDirElement = Route.GetFixedPrefDirElementAt(180, x);
2793  }
2794  if(!BreakFlag)
2795  {
2796  if(PrefDirElement.GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
2797  {
2798  RailwayImage->Canvas->Draw((PrefDirElement.HLoc - Track->GetHLocMin()) * 16, (PrefDirElement.VLoc - Track->GetVLocMin()) * 16,
2799  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
2800  }
2801  }
2802  }
2803  }
2804  TrainController->WriteTrainsToImage(0, RailwayImage);
2805  RailwayImage->SaveToFile(ImageFileName);
2806  delete RailwayImage;
2807  TrainController->BaseTime = TDateTime::CurrentDateTime();
2809  Screen->Cursor = TCursor(-2); // Arrow
2810  Utilities->CallLogPop(1703);
2811  }
2812  catch(const Exception &e)
2813  {
2814  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2815  {
2816  Screen->Cursor = TCursor(-2); // Arrow;
2817  UnicodeString MessageStr = "Insufficient memory available to store this image";
2818  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2819  }
2820  else
2821  {
2822  ErrorLog(113, e.Message);
2823  }
2824  }
2825 }
2826 
2827 // ---------------------------------------------------------------------------
2828 
2829 void __fastcall TInterface::SaveHeaderMenu1Click(TObject *Sender)
2830 {
2831 //
2832  try
2833  {
2834  TrainController->LogEvent("SaveHeaderMenu1Click");
2835  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveHeaderMenu1Click");
2836  if(Sender == SaveSessionButton)
2837  {
2838  SaveSessionFlag = true;
2839  }
2840  else if(SavedFileName == "") // use 'Save As' function
2841  {
2842  SaveAsSubroutine(1);
2843  }
2844  else // ordinary save
2845  {
2846  Screen->Cursor = TCursor(-11); // Hourglass;
2847  std::ofstream VecFile(SavedFileName.c_str());
2848  if(!(VecFile.fail()))
2849  {
2853  // save track elements
2854  if(Track->UserGraphicVector.empty())
2855  {
2856  Track->SaveTrack(9, VecFile, false); // false for no graphics (**Active elements** saved as marker)
2857  }
2858  else
2859  {
2860  Track->SaveTrack(10, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
2861  }
2862  // save text elements
2863  TextHandler->SaveText(5, VecFile);
2864  // save PrefDir elements
2865  EveryPrefDir->SavePrefDirVector(8, VecFile);
2866  if(!Track->UserGraphicVector.empty())
2867  {
2868  // save user graphics
2869  Track->SaveUserGraphics(1, VecFile);
2870  }
2871  FileChangedFlag = false;
2872  VecFile.close();
2873  }
2874  else
2875  ShowMessage("Railway failed to save - can't open file");
2876  Screen->Cursor = TCursor(-2); // Arrow
2877  }
2878  Utilities->CallLogPop(1552);
2879  }
2880  catch(const Exception &e)
2881  {
2882  ErrorLog(44, e.Message);
2883  }
2884 }
2885 
2886 // ---------------------------------------------------------------------------
2887 void __fastcall TInterface::LoadSessionMenuItemClick(TObject *Sender)
2888 {
2889  try
2890  {
2891  TrainController->LogEvent("LoadSessionMenuItemClick");
2892  LoadSessionFlag = true; // load session within ClockTimer2
2893  }
2894  catch(const Exception &e)
2895  {
2896  ErrorLog(136, e.Message);
2897  }
2898 }
2899 
2900 // ---------------------------------------------------------------------------
2901 void __fastcall TInterface::ClearAllMenuItemClick(TObject *Sender)
2902 {
2903  try
2904  {
2905  TrainController->LogEvent("ClearAllMenuItemClick");
2906  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ClearAllMenuItemClick");
2907  if(ClearEverything(2))
2908  {;
2909  } // no change in action on result
2910  Level1Mode = BaseMode;
2911  SetLevel1Mode(126);
2912  Utilities->CallLogPop(1179);
2913  }
2914  catch(const Exception &e)
2915  {
2916  ErrorLog(137, e.Message);
2917  }
2918 }
2919 
2920 // ---------------------------------------------------------------------------
2921 void __fastcall TInterface::ExportTTMenuItemClick(TObject *Sender)
2922 { // no need to stop clock as can't be called when railway operating
2923  try
2924  {
2925  TrainController->LogEvent("ExportTTMenuItemClick");
2926  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExportTTMenuItemClick");
2927  if(!DirectoryExists(CurDir + "\\" + FORMATTEDTT_DIR_NAME))
2928  {
2929  ShowMessage("Failed to find folder " + FORMATTEDTT_DIR_NAME + " in the folder where 'railway.exe' resides. Timetable can't be exported");
2930  Utilities->CallLogPop(1699);
2931  return;
2932  }
2933  Screen->Cursor = TCursor(-11); // Hourglass;
2934  // no need to stop clock as can't select this if operating
2936  Screen->Cursor = TCursor(-2); // Arrow
2937  Utilities->CallLogPop(1573);
2938  }
2939  catch(const Exception &e)
2940  {
2941  ErrorLog(138, e.Message);
2942  }
2943 }
2944 // ---------------------------------------------------------------------------
2945 // Timetable editing functions
2946 
2947 /* Note that during early development the timetable was created outside the program as a .csv file using Excel, it was only later that
2948  the editing functions within the program were developed. Much of the original structure was preserved though to avoid rewriting the
2949  code interpretation functions in TrainUnit.cpp. This is why commas are used as service event separators, and why it is necessary to
2950  convert them to CRLFs for display and back again for internal storage. It is acknowledged that all this makes the editing functions
2951  somewhat cumbersome, and, as ever, if I was starting again I wouldn't do it like that!
2952 
2953  CR & LF review:
2954  These cause problems by the way that different subroutines handle them.
2955 
2956  AnsiStrings can incorporate CRLFs, but the end of an AnsiString is marked by a '\0' character as in 'C' strings.
2957 
2958  In the fstream functions 'getline(char_type* s, streamsize n)' extracts characters from the stream and puts them in buffer 's' until
2959  (a) n-1 characters are stored + '\0' after the n-1 characters;
2960  (b) a '\n' (CRLF) character is found in the stream, in which case a '\0' is added to the buffer after the text that immediately
2961  precedes the CRLF in the stream; and
2962  (c) an eof() is found in the stream, in which case a '\0' is added to the buffer at the end of the text.
2963  Note that if no characters are stored a '\0' is still stored in position [0] of the buffer.
2964 
2965  The << operator in ofstreams, when used with a null terminated string, doesn't store the null. If it is required it has to be
2966  sent explicitly, e.g. file << '\0'. Presumably the same applies for CRLF terminated strings.
2967 
2968 */
2969 // ---------------------------------------------------------------------------
2970 
2971 void __fastcall TInterface::CreateTimetableMenuItemClick(TObject *Sender)
2972 {
2973  try
2974  {
2975  TrainController->LogEvent("CreateTimetableMenuItemClick");
2976  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CreateTimetableMenuItemClick");
2977  CreateEditTTFileName = "";
2978  TimetableEditVector.clear();
2979  TimetableEditPanel->Visible = true;
2980  HighlightPanel->Visible = false;
2981  TimetablePanel->Visible = true;
2982  TimetablePanel->BringToFront(); // in case SaveRailway button visible, want it hidden else obscures the panel text
2983  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
2984  OneEntryTimetableMemo->Clear();
2985  AllEntriesTTListBox->Clear();
2986  TTStartTimeBox->Text = "";
2987  AddSubMinsBox->Text = "";
2989  LocationNameComboBox->Clear();
2990  TimetableTitle = ""; // unload any loaded timetable. Added here at v2.1.0
2991  TrainController->TrainDataVector.clear(); // unload any loaded timetable. Added here at v2.1.0
2992  SetCaption(9); // added at v2.1.0 as formerly retained earlier loaded tt name in error
2993  TimetableChangedFlag = false;
2994  TimetableValidFlag = false;
2995  TTEntryChangedFlag = false;
2997  AZOrderButton->Caption = AnsiString("A-Z Order");
2998  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
2999  CopiedEntryFlag = false;
3000  NewEntryInPreparationFlag = false;
3001  CopiedEntryStr = "";
3002  TEVPtr = 0;
3004  TTFirstServicePtr = 0;
3005  TTLastServicePtr = 0; // all set to null to begin with
3006 
3007 // populate LocationNameComboBox if a railway is loaded, but first compile the ActiveTrackElementNameMap
3008  TTrack::TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
3010  for(unsigned int x = 0; x < Track->TrackVector.size(); x++)
3011  {
3012  if((Track->TrackVector.at(x).ActiveTrackElementName != "") && (Track->ContinuationNameMap.find(Track->TrackVector.at(x).ActiveTrackElementName))
3013  == Track->ContinuationNameMap.end())
3014  { // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
3015  ActiveTrackElementNameMapEntry.first = Track->TrackVector.at(x).ActiveTrackElementName;
3016  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
3017  Track->ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
3018  }
3019  }
3021  if(!(Track->ActiveTrackElementNameMap.empty()))
3022  {
3023  LocationNameComboBox->Text = "Location names";
3024 // new version at beta v0.2b
3026  ATENIT++)
3027  {
3028  LocationNameComboBox->Items->Add(ATENIT->first); // continuations excluded during compilation, but a location that includes
3029  // continuations as well as other track will be included - earlier version
3030  // would have excluded them
3031  }
3032 
3033 /* old version using LocationNameMultiMap, changed to use ActiveTrackElementNames to avoid including lone concourses and named non-station
3034  locations
3035  TStringList *StringList = new TStringList;
3036  StringList->Clear();//probably already empty but help file doesn't say so
3037  StringList->Sorted = false;//for now
3038  for(TTrack::TLocationNameMultiMapIterator LNMIT = Track->LocationNameMultiMap.begin(); LNMIT != Track->LocationNameMultiMap.end(); LNMIT++)
3039  {
3040  NewKey = LNMIT->first;
3041  if(OldKey != NewKey)//only add new values
3042  {
3043  if(Track->ContinuationNameMap.find(NewKey) == Track->ContinuationNameMap.end())//not a continuation
3044  {
3045  StringList->Add(NewKey);
3046  OldKey = NewKey;
3047  }
3048  }
3049  }
3050  StringList->Sort();
3051  for(int x=0;x<StringList->Count;x++)
3052  {
3053  LocationNameComboBox->Items->Add(StringList->Strings[x]);
3054  }
3055  delete StringList;
3056 */
3057  }
3058  else
3059  {
3060  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
3061  }
3063  SetLevel1Mode(82);
3064  Utilities->CallLogPop(1595);
3065  }
3066  catch(const Exception &e)
3067  {
3068  ErrorLog(47, e.Message);
3069  }
3070 }
3071 
3072 // ---------------------------------------------------------------------------
3073 void __fastcall TInterface::EditTimetableMenuItemClick(TObject *Sender)
3074 /* The .ttb file contains a sequence of AnsiStrings separated by null characters. CRLFs may be embedded within the AnsiStrings,
3075  * to cause newlines when displayed. Each AnsiString corresponds to a timetable 'entry'
3076 */
3077 {
3078  try
3079  {
3080  TrainController->LogEvent("EditTimetableMenuItemClick");
3081  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EditTimetableMenuItemClick");
3082  TimetableDialog->Filter = "Timetable file (*.ttb)|*ttb";
3083  CreateEditTTFileName = "";
3084  TimetableEditVector.clear();
3085  TimetableEditPanel->Visible = true;
3086  HighlightPanel->Visible = false;
3087  TimetablePanel->Visible = true;
3088  TimetablePanel->BringToFront(); // in case SaveRailway button visible, want it hidden else obscures the panel text
3089  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3090  OneEntryTimetableMemo->Clear();
3091  AllEntriesTTListBox->Clear();
3092  TTStartTimeBox->Text = "";
3093  AddSubMinsBox->Text = "";
3095  LocationNameComboBox->Clear();
3096  TimetableTitle = ""; // unload any loaded timetable. Moved here from below at v2.1.0 for consistency with CreateTimetable
3097  TrainController->TrainDataVector.clear(); // unload any loaded timetable. Moved here from below at v2.1.0 for consistency with CreateTimetable
3098  SetCaption(8); // added at v2.1.0 as formerly retained earlier loaded tt name in error
3099  TEVPtr = 0;
3101  TTFirstServicePtr = 0;
3102  TTLastServicePtr = 0; // all set to null to begin with
3103  if(TimetableDialog->Execute())
3104  {
3105  CreateEditTTFileName = AnsiString(TimetableDialog->FileName);
3106  TrainController->LogEvent("EditTimetable " + CreateEditTTFileName);
3107  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary); // open in binary to examine each character
3108  if(TTBLFile.is_open())
3109  {
3110  // check doesn't contain any non-ascii characters except CR, LF & '\0', and isn't empty
3111  char c;
3112  while(!TTBLFile.eof())
3113  {
3114  TTBLFile.get(c);
3115  if((c < 32) && (c != 13) && (c != 10) && (c != '\0')) // char is signed by default so values > 127 will be caught as treated as -ve
3116  {
3117  ShowMessage("Timetable file is empty or contains non-ascii characters, codes must be between 20 and 127, or CR or LF");
3118  TTBLFile.close();
3119  Utilities->CallLogPop(1612);
3120  return;
3121  }
3122  }
3123  TTBLFile.close();
3124  }
3125  else
3126  {
3127  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
3128  Utilities->CallLogPop(1597);
3129  return;
3130  }
3131  // reopen again in binary mode so the "\r\n" pairs stay as they are rather than being entered as '\n'
3132  Delay(4, 100); // 100mSec delay between closing & re-opening file
3133  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary);
3134  if(TTBLFile.is_open())
3135  {
3136  TTBLFile.clear(); // to clear eofbit from last read
3137  TTBLFile.seekg(0); // shouldn't be needed but include for safety
3138  TimetableChangedFlag = false;
3139  TimetableValidFlag = false;
3140  TTEntryChangedFlag = false;
3142  AZOrderButton->Caption = AnsiString("A-Z Order");
3143  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
3144  NewEntryInPreparationFlag = false;
3145  CopiedEntryStr = "";
3146  CopiedEntryFlag = false;
3147 // CreateEditTTFileName = TimetableDialog->FileName;
3148  for(int x = CreateEditTTFileName.Length(); x > 0; x--)
3149  {
3150  if(CreateEditTTFileName[x] == '\\')
3151  {
3152  CreateEditTTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
3153  break;
3154  }
3155  }
3156  char *TimetableEntryString = new char[10000];
3157  while(true)
3158  {
3159  TTBLFile.getline(TimetableEntryString, 10000, '\0'); // pick up the entire AnsiString, including any embedded newlines
3160  if(TTBLFile.eof() && (TimetableEntryString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
3161  { // may still have eof even if read a line, and
3162  // if so need to process it
3163  break;
3164  }
3165  AnsiString OneLine(TimetableEntryString);
3166  TimetableEditVector.push_back(OneLine);
3167  }
3168  TTBLFile.close();
3169  delete TimetableEntryString;
3170  // here with TimetableEditVector compiled
3171  }
3172  else
3173  {
3174  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
3175  Utilities->CallLogPop(1654);
3176  return;
3177  }
3178  }
3179  else // cancelled dialog [section prior to CallLogPop added for v1.3.2 to clear timetable screen if cancel button pressed]
3180  {
3181  CreateEditTTFileName = "";
3182 // set to null to allow a check during error file saving, if not null save the tt being edited to the file (see entry in ExitTTModeButtonClick)
3183  CreateEditTTTitle = ""; // as above
3184  Level1Mode = BaseMode;
3185  SetLevel1Mode(132);
3186  Utilities->CallLogPop(1633);
3187  return;
3188  }
3189 
3191  if(TimetableEditVector.empty())
3192  {
3194  SetLevel1Mode(89);
3195  Utilities->CallLogPop(1614);
3196  return;
3197  }
3198 
3199 // all now set where can be
3201 
3202 // populate LocationNameComboBox if a railway is loaded, but first compile the ActiveTrackElementNameMap
3203  TTrack::TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
3205  for(unsigned int x = 0; x < Track->TrackVector.size(); x++)
3206  {
3207  if((Track->TrackVector.at(x).ActiveTrackElementName != "") && (Track->ContinuationNameMap.find(Track->TrackVector.at(x).ActiveTrackElementName))
3208  == Track->ContinuationNameMap.end())
3209  { // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
3210  ActiveTrackElementNameMapEntry.first = Track->TrackVector.at(x).ActiveTrackElementName;
3211  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
3212  Track->ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
3213  }
3214  }
3216  if(!(Track->ActiveTrackElementNameMap.empty()))
3217  {
3218  LocationNameComboBox->Text = "Location names";
3219 // new version for beta v0.2b
3221  ATENIT++)
3222  {
3223  LocationNameComboBox->Items->Add(ATENIT->first); // continuations excluded during compilation, but a location that includes
3224  // continuations as well as other track will be included - earlier version
3225  // would have excluded them
3226  }
3227  }
3228  else
3229  {
3230  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
3231  }
3233  SetLevel1Mode(83);
3234  Utilities->CallLogPop(1596);
3235  }
3236  catch(const Exception &e)
3237  {
3238  ErrorLog(48, e.Message);
3239  }
3240 }
3241 // ---------------------------------------------------------------------------
3242 
3243 void __fastcall TInterface::ShowHideTTButtonClick(TObject *Sender)
3244 {
3245  try
3246  {
3247  TrainController->LogEvent("ShowHideTTButtonClick");
3248  if(TimetableEditPanel->Visible)
3249  {
3250  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Show");
3251  TimetableEditPanel->Visible = false;
3252  ShowHideTTButton->Hint = "Show the timetable editor Shift S";
3253 // InfoPanel->Visible = false; //changed at v1.3.0 to make it clearer that still in TT mode
3254  InfoPanel->Caption = "Timetable mode: editor hidden"; // as above
3255  }
3256  else
3257  {
3258  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3259  TimetableEditPanel->Visible = true;
3260  ShowHideTTButton->Hint = "Hide the timetable editor to see the railway Shift H";
3262  SetLevel1Mode(124);
3263  }
3264  }
3265  catch(const Exception &e)
3266  {
3267  ErrorLog(139, e.Message);
3268  }
3269 }
3270 // ---------------------------------------------------------------------------
3271 
3272 void __fastcall TInterface::NextTTEntryButtonClick(TObject *Sender)
3273 {
3274  try
3275  {
3276  TrainController->LogEvent("NextTTEntryButtonClick");
3277  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NextTTEntryButtonClick");
3278  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
3279  {
3280  Utilities->CallLogPop(1683);
3281  return;
3282  }
3283  if(TTCurrentEntryPtr < (TimetableEditVector.end() - 1))
3285  TTEntryChangedFlag = false;
3286  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3287  // position changing in AllEntriesTTListBox
3289  SetLevel1Mode(85);
3290  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3291  {
3293  }
3294  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3295  {
3296  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3297  }
3298  else
3299  {
3300  AllEntriesTTListBox->TopIndex = TopPos;
3301  }
3302  Utilities->CallLogPop(1605);
3303  }
3304  catch(const Exception &e)
3305  {
3306  ErrorLog(50, e.Message);
3307  }
3308 }
3309 
3310 // ---------------------------------------------------------------------------
3311 void __fastcall TInterface::PreviousTTEntryButtonClick(TObject *Sender)
3312 {
3313  try
3314  {
3315  TrainController->LogEvent("PreviousTTEntryButtonClick");
3316  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PreviousTTEntryButtonClick");
3317  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
3318  {
3319  Utilities->CallLogPop(1684);
3320  return;
3321  }
3324  TTEntryChangedFlag = false;
3325  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3326  // position changing in AllEntriesTTListBox
3328  SetLevel1Mode(86);
3329  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3330  {
3332  }
3333  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3334  {
3335  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3336  }
3337  else
3338  {
3339  AllEntriesTTListBox->TopIndex = TopPos;
3340  }
3341  Utilities->CallLogPop(1607);
3342  }
3343  catch(const Exception &e)
3344  {
3345  ErrorLog(51, e.Message);
3346  }
3347 }
3348 
3349 // ---------------------------------------------------------------------------
3350 void __fastcall TInterface::NewTTEntryButtonClick(TObject *Sender)
3351 {
3352  try
3353  {
3354  TrainController->LogEvent("NewTTEntryButtonClick");
3355  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NewTTEntryButtonClick");
3356  OneEntryTimetableMemo->Clear();
3357  OneEntryTimetableMemo->SetFocus();
3360  SetLevel1Mode(103);
3361  Utilities->CallLogPop(1615);
3362  }
3363  catch(const Exception &e)
3364  {
3365  ErrorLog(52, e.Message);
3366  }
3367 }
3368 // ---------------------------------------------------------------------------
3369 
3370 void __fastcall TInterface::AddMinsButtonClick(TObject *Sender)
3371 {
3372  try
3373  {
3374  TrainController->LogEvent("AddMinsButtonClick");
3375  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddMinsButtonClick");
3376  bool ValidFlag = true;
3377  for(int x = 1; x <= AddSubMinsBox->Text.Length(); x++)
3378  {
3379  if((AddSubMinsBox->Text[x] > '9') || (AddSubMinsBox->Text[x] < '0')) // tested in TTHandler but check here as a safeguard
3380  {
3381  ValidFlag = false;
3382  break;
3383  }
3384  }
3385  if(ValidFlag)
3386  {
3387  if(AddSubMinsBox->Text.ToInt() == 0)
3388  ValidFlag = false;
3389  }
3390  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == "") || (AddSubMinsBox->Text == "") || !ValidFlag)
3391  {
3392  Utilities->CallLogPop(1649);
3393  return;
3394  }
3395  TDateTime DummyTime;
3396  int AddMins = AddSubMinsBox->Text.ToInt();
3397  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3398  {
3399  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
3400  {
3401  if(TrainController->CheckTimeValidity(25, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
3402  {
3403  int Mins = OneEntryTimetableMemo->Lines->Strings[x].SubString(y + 3, 2).ToInt();
3404  int Hrs = OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 2).ToInt();
3405  Mins += AddMins;
3406  while(Mins >= 60)
3407  {
3408  Mins -= 60;
3409  Hrs++;
3410  }
3411  if(Hrs > 95)
3412  {
3413  ShowMessage("One or more times excessive, not permitted to exceed 95 hours");
3414  Utilities->CallLogPop(1650);
3415  return;
3416  }
3417  AnsiString MinsStr = AnsiString(Mins), HrsStr = AnsiString(Hrs);
3418  if(Mins < 10)
3419  MinsStr = "0" + MinsStr;
3420  if(Hrs < 10)
3421  HrsStr = "0" + HrsStr;
3422  int StrLength = OneEntryTimetableMemo->Lines->Strings[x].Length();
3423  AnsiString NewString = OneEntryTimetableMemo->Lines->Strings[x].SubString(1, (y - 1)); // up to but not including the time
3424  NewString += HrsStr + ':' + MinsStr;
3425  NewString += OneEntryTimetableMemo->Lines->Strings[x].SubString((y + 5), (StrLength - y - 4));
3426  OneEntryTimetableMemo->Lines->Strings[x] = NewString;
3427  }
3428  }
3429  }
3430 
3431  OneEntryTimetableMemo->HideSelection = true;
3432  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
3433  OneEntryTimetableMemo->SelLength = 0;
3434  TimetableValidFlag = false;
3435  TimetableChangedFlag = true;
3436  TTEntryChangedFlag = true;
3438  SetLevel1Mode(91);
3439  Utilities->CallLogPop(1617);
3440  }
3441  catch(const Exception &e)
3442  {
3443  ErrorLog(54, e.Message);
3444  }
3445 }
3446 // ---------------------------------------------------------------------------
3447 
3448 void __fastcall TInterface::SubMinsButtonClick(TObject *Sender)
3449 {
3450  try
3451  {
3452  TrainController->LogEvent("SubMinsButtonClick");
3453  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SubMinsButtonClick");
3454  bool ValidFlag = true;
3455  for(int x = 1; x <= AddSubMinsBox->Text.Length(); x++)
3456  {
3457  if((AddSubMinsBox->Text[x] > '9') || (AddSubMinsBox->Text[x] < '0')) // tested in TTHandler but check here as a safeguard
3458  {
3459  ValidFlag = false;
3460  break;
3461  }
3462  }
3463  if(ValidFlag)
3464  {
3465  if(AddSubMinsBox->Text.ToInt() == 0)
3466  ValidFlag = false;
3467  }
3468  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == "") || (AddSubMinsBox->Text == "") || !ValidFlag)
3469  {
3470  Utilities->CallLogPop(1659);
3471  return;
3472  }
3473  TDateTime DummyTime;
3474  int SubMins = AddSubMinsBox->Text.ToInt();
3475  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3476  {
3477  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
3478  {
3479  if(TrainController->CheckTimeValidity(28, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
3480  {
3481  int Mins = OneEntryTimetableMemo->Lines->Strings[x].SubString(y + 3, 2).ToInt();
3482  int Hrs = OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 2).ToInt();
3483  Mins -= SubMins;
3484  while(Mins < 0)
3485  {
3486  Mins += 60;
3487  Hrs--;
3488  }
3489  if(Hrs < 0)
3490  {
3491  ShowMessage("One or more times are now before 00:00, this is not permitted");
3492  Utilities->CallLogPop(1660);
3493  return;
3494  }
3495  AnsiString MinsStr = AnsiString(Mins), HrsStr = AnsiString(Hrs);
3496  if(Mins < 10)
3497  MinsStr = "0" + MinsStr;
3498  if(Hrs < 10)
3499  HrsStr = "0" + HrsStr;
3500  int StrLength = OneEntryTimetableMemo->Lines->Strings[x].Length();
3501  AnsiString NewString = OneEntryTimetableMemo->Lines->Strings[x].SubString(1, (y - 1)); // up to but not including the time
3502  NewString += HrsStr + ':' + MinsStr;
3503  NewString += OneEntryTimetableMemo->Lines->Strings[x].SubString((y + 5), (StrLength - y - 4));
3504  OneEntryTimetableMemo->Lines->Strings[x] = NewString;
3505  }
3506  }
3507  }
3508  OneEntryTimetableMemo->HideSelection = true;
3509  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
3510  OneEntryTimetableMemo->SelLength = 0;
3511  TimetableValidFlag = false;
3512  TimetableChangedFlag = true;
3513  TTEntryChangedFlag = true;
3515  SetLevel1Mode(92);
3516  Utilities->CallLogPop(1618);
3517  }
3518  catch(const Exception &e)
3519  {
3520  ErrorLog(55, e.Message);
3521  }
3522 }
3523 // ---------------------------------------------------------------------------
3524 
3525 void __fastcall TInterface::CopyTTEntryButtonClick(TObject *Sender)
3526 {
3527  try
3528  {
3529  TrainController->LogEvent("CopyTTEntryButtonClick");
3530  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CopyTTEntryButtonClick");
3531  if(TTCurrentEntryPtr == 0)
3532  {
3533  Utilities->CallLogPop(1636);
3534  return;
3535  }
3537  CopiedEntryFlag = true;
3538  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3539  // position changing in AllEntriesTTListBox
3541  SetLevel1Mode(93);
3542  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3543  {
3545  }
3546  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3547  {
3548  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3549  }
3550  else
3551  {
3552  AllEntriesTTListBox->TopIndex = TopPos;
3553  }
3554  Utilities->CallLogPop(1619);
3555  }
3556  catch(const Exception &e)
3557  {
3558  ErrorLog(56, e.Message);
3559  }
3560 }
3561 // ---------------------------------------------------------------------------
3562 
3563 void __fastcall TInterface::CutTTEntryButtonClick(TObject *Sender)
3564 {
3565  try
3566  {
3567  TrainController->LogEvent("CutTTEntryButtonClick");
3568  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CutTTEntryButtonClick");
3569  if(TTCurrentEntryPtr == 0) // || (*TTCurrentEntryPtr == ""))//safeguard
3570  {
3571  Utilities->CallLogPop(1674);
3572  return;
3573  }
3575  CopiedEntryFlag = true;
3576  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an erase,
3577  // so use the position in the vector
3579 // now need to rebuild all the pointers & the AllEntriesTTListBox so repeat the process from EditTimetableMenuItemClick
3580 // pick up the start time if there is one
3581  TimetableChangedFlag = true;
3582  TimetableValidFlag = false;
3583  TTEntryChangedFlag = false;
3584  TEVPtr = 0;
3586  TTFirstServicePtr = 0;
3587  TTLastServicePtr = 0; // all set to null to begin with
3588  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3589  // position changing in AllEntriesTTListBox
3590  AllEntriesTTListBox->Clear();
3592  if(TimetableEditVector.empty())
3593  {
3595  SetLevel1Mode(109);
3596  Utilities->CallLogPop(1777);
3597  return;
3598  }
3599 
3600 // reset the TTCurrentEntryPtr to the Entry after the erased one if there is one
3601 // but vector pointers unreliable after an erase, so use the position in the vector
3602  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
3603  {
3605  }
3606  else
3607  {
3608  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos; // no need to add one as will be one further on because of erase
3609  }
3610  if(TTCurrentEntryPtr == 0)
3611  {
3612  OneEntryTimetableMemo->Clear();
3613  }
3615  SetLevel1Mode(115);
3616  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3617  {
3619  }
3620  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3621  {
3622  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3623  }
3624  else
3625  {
3626  AllEntriesTTListBox->TopIndex = TopPos;
3627  }
3628  Utilities->CallLogPop(1676);
3629  }
3630  catch(const Exception &e)
3631  {
3632  ErrorLog(111, e.Message);
3633  }
3634 }
3635 
3636 // ---------------------------------------------------------------------------
3637 void __fastcall TInterface::PasteTTEntryButtonClick(TObject *Sender)
3638 {
3639  try
3640  {
3641  TrainController->LogEvent("PasteTTEntryButtonClick");
3642  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PasteTTEntryButtonClick");
3643  if(TTCurrentEntryPtr == 0) // || (CopiedEntryStr == "")) allow blank copies
3644  {
3645  Utilities->CallLogPop(1637);
3646  return;
3647  }
3648  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
3649  TimetableEditVector.insert(TTCurrentEntryPtr + 1, CopiedEntryStr); // inserts before the indicated pointer position, i.e. immediately
3650  // after the current Entry - may be at the end
3651  TimetableChangedFlag = true;
3652  TimetableValidFlag = false;
3653  TTEntryChangedFlag = false;
3654  TEVPtr = 0;
3656  TTFirstServicePtr = 0;
3657  TTLastServicePtr = 0; // all set to null to begin with
3658  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3659  // position changing in AllEntriesTTListBox
3660  AllEntriesTTListBox->Clear();
3662  if(TimetableEditVector.empty())
3663  {
3665  SetLevel1Mode(110);
3666  Utilities->CallLogPop(1778);
3667  return;
3668  }
3669 // restore TTCurrentEntryPtr
3670  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
3671  TTCurrentEntryPtr++; // advance the pointer to the pasted entry
3672 // CopiedEntryStr = "";//revert to null - no, allow multiple copies
3674  SetLevel1Mode(94);
3675  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3676  {
3678  }
3679  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3680  {
3681  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3682  }
3683  else
3684  {
3685  AllEntriesTTListBox->TopIndex = TopPos;
3686  }
3687  Utilities->CallLogPop(1620);
3688  }
3689  catch(const Exception &e)
3690  {
3691  ErrorLog(57, e.Message);
3692  }
3693 }
3694 // ---------------------------------------------------------------------------
3695 
3696 void __fastcall TInterface::DeleteTTEntryButtonClick(TObject *Sender)
3697 {
3698  try
3699  {
3700  TrainController->LogEvent("DeleteTTEntryButtonClick");
3701  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteTTEntryButtonClick");
3702  if(TTCurrentEntryPtr == 0)
3703  {
3704  Utilities->CallLogPop(1645);
3705  return;
3706  }
3707  UnicodeString MessageStr = "Are you sure this entry should be deleted?";
3708  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
3709  if(button == IDNO)
3710  {
3711  Utilities->CallLogPop(1663);
3712  return;
3713  }
3714  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an erase,
3715  // so use the position in the vector
3717 
3718 // now need to rebuild all the pointers & the AllEntriesTTListBox so repeat the process from EditTimetableMenuItemClick
3719 // pick up the start time if there is one
3720  TimetableChangedFlag = true;
3721  TimetableValidFlag = false;
3722  TTEntryChangedFlag = false;
3723  TEVPtr = 0;
3725  TTFirstServicePtr = 0;
3726  TTLastServicePtr = 0; // all set to null to begin with
3727  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3728  // position changing in AllEntriesTTListBox
3729  AllEntriesTTListBox->Clear();
3731  if(TimetableEditVector.empty())
3732  {
3734  SetLevel1Mode(111);
3735  Utilities->CallLogPop(1779);
3736  return;
3737  }
3738 // reset the TTCurrentEntryPtr to the Entry after the erased one if there is one
3739 // but vector pointers unreliable after an erase, so use the position in the vector
3740  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
3741  {
3743  }
3744  else
3745  {
3746  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos; // no need to add one as will be one further on because of erase
3747  }
3748  if(TTCurrentEntryPtr == 0)
3749  {
3750  OneEntryTimetableMemo->Clear();
3751  }
3753  SetLevel1Mode(95);
3754  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3755  {
3757  }
3758  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3759  {
3760  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3761  }
3762  else
3763  {
3764  AllEntriesTTListBox->TopIndex = TopPos;
3765  }
3766  Utilities->CallLogPop(1621);
3767  }
3768  catch(const Exception &e)
3769  {
3770  ErrorLog(58, e.Message);
3771  }
3772 }
3773 // ---------------------------------------------------------------------------
3774 
3775 void __fastcall TInterface::SaveTTEntryButtonClick(TObject *Sender)
3776 {
3777  try
3778  {
3779  TrainController->LogEvent("SaveTTEntryButtonClick");
3780  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTEntryButtonClick");
3781 /* allow blank lines to be saved
3782  AnsiString ContentStr = OneEntryTimetableMemo->Text;
3783  if((ContentStr == "\r\n") || (ContentStr == "\n") || (ContentStr == ""))
3784  {
3785  Utilities->CallLogPop(1679);
3786  return;
3787  }
3788 */
3789  AnsiString TempStr = "";
3790  bool ActiveLine = false;
3791  if(TTCurrentEntryPtr > 0)
3792  {
3793  if(*TTCurrentEntryPtr != "")
3794  {
3796  {
3797  ActiveLine = true;
3798  // need to add commas after each line in OneEntryTimetableMemo exept the last, where have '\0'
3799  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3800  {
3801  for(int y = 1; y <= OneEntryTimetableMemo->Lines->Strings[x].Length(); y++)
3802  {
3803  TempStr += OneEntryTimetableMemo->Lines->Strings[x][y];
3804  }
3805  if(x < (OneEntryTimetableMemo->Lines->Count - 1))
3806  {
3807  TempStr += ',';
3808  }
3809  // No need to add a '\n' as a '\0' is added automatically as a string delimiter. If add '\n' then it is treated as a blank line and
3810  // ends the timetable
3811  }
3812  // strip any excess commas from the end
3813  if(TempStr != "")
3814  {
3815  while(TempStr[TempStr.Length()] == ',')
3816  {
3817  TempStr = TempStr.SubString(1, TempStr.Length() - 1);
3818  if(TempStr == "")
3819  break;
3820  }
3821  }
3822  }
3823  }
3824  }
3825  if(!ActiveLine)
3826  {
3827  TempStr = OneEntryTimetableMemo->Text; // Note that if the entry was intended as a service but goes in as plain text because
3828  // the service & entry pointers aren't yet set, then CRLFs will be converted to commas in
3829  // CompileAllEntriesMemoAndSetPointers if it appears after the start time
3830  // and before a blank line or end of file, so the syntax check will work OK
3831  }
3832  if(AZOrderButton->Caption == AnsiString("Original Order"))
3833  {
3835  }
3836  TimetableValidFlag = false;
3837  TimetableChangedFlag = true;
3838  TTEntryChangedFlag = false;
3839  int TopPos;
3840  if(TTCurrentEntryPtr == 0)
3841  {
3843  }
3845  {
3846  (*TTCurrentEntryPtr) = TempStr;
3847  // need to reset the AllEntriesTTListBox in case the headcode has changed
3848  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
3849  TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3850  // position changing in AllEntriesTTListBox
3851  AllEntriesTTListBox->Clear();
3853  if(TimetableEditVector.empty())
3854  {
3856  SetLevel1Mode(112);
3857  Utilities->CallLogPop(1780);
3858  return;
3859  }
3860  // restore TTCurrentEntryPtr
3861  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
3862  }
3863  else
3864  {
3865  NewEntryInPreparationFlag = false;
3866  if(TTCurrentEntryPtr != 0)
3867  {
3868  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
3869  TimetableEditVector.insert(TTCurrentEntryPtr + 1, TempStr); // inserts before the indicated pointer position, which may be at the end
3870  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
3872  }
3873  else
3874  {
3875  TimetableEditVector.insert(TimetableEditVector.end(), TempStr); // inserts before the indicated pointer position
3877  }
3878  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the current position
3879  TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3880  // position changing in AllEntriesTTListBox
3881  AllEntriesTTListBox->Clear();
3883  if(TimetableEditVector.empty())
3884  {
3886  SetLevel1Mode(113);
3887  Utilities->CallLogPop(1781);
3888  return;
3889  }
3890 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
3891  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
3892  {
3894  }
3895  else
3896  {
3897  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
3898  }
3899  }
3901  SetLevel1Mode(96);
3902  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3903  {
3905  }
3906  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3907  {
3908  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3909  }
3910  else
3911  {
3912  AllEntriesTTListBox->TopIndex = TopPos;
3913  }
3914  Utilities->CallLogPop(1622);
3915  }
3916  catch(const Exception &e)
3917  {
3918  ErrorLog(59, e.Message);
3919  }
3920 }
3921 // ---------------------------------------------------------------------------
3922 
3923 void __fastcall TInterface::SaveTTButtonClick(TObject *Sender)
3924 {
3925  try
3926  {
3927  TrainController->LogEvent("SaveTTButtonClick");
3928  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTButtonClick");
3929  if(TimetableEditVector.empty())
3930  {
3931  ShowMessage("Timetable is empty, can't save an empty timetable");
3932  Utilities->CallLogPop(1685);
3933  return;
3934  }
3935  std::ofstream TTBLFile;
3936  if(CreateEditTTFileName != "")
3937  {
3938  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
3939  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
3940  }
3941  else
3942  {
3943  if(SaveTTDialog->Execute())
3944  {
3945  CreateEditTTFileName = AnsiString(SaveTTDialog->FileName);
3946  for(int x = CreateEditTTFileName.Length(); x > 0; x--)
3947  {
3948  if(CreateEditTTFileName[x] == '\\')
3949  {
3950  CreateEditTTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
3951  break;
3952  }
3953  }
3954  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
3955  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
3956  }
3957  }
3958  if(TTBLFile.is_open())
3959  {
3960  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
3961  {
3962  TTBLFile << (*TEVPtr).c_str() << '\0';
3963  }
3964  TimetableChangedFlag = false;
3965  TTBLFile.close();
3966  }
3967  else
3968  {
3969  ShowMessage(CreateEditTTFileName + " failed to open, ensure not already open in another application");
3970  }
3972  SetLevel1Mode(97);
3973  Utilities->CallLogPop(1623);
3974  }
3975  catch(const Exception &e)
3976  {
3977  ErrorLog(60, e.Message);
3978  }
3979 }
3980 // ---------------------------------------------------------------------------
3981 
3982 void __fastcall TInterface::SaveTTAsButtonClick(TObject *Sender)
3983 {
3984  try
3985  {
3986  TrainController->LogEvent("SaveTTAsButtonClick");
3987  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTAsButtonClick");
3988  if(TimetableEditVector.empty())
3989  {
3990  ShowMessage("Timetable is empty, can't save an empty timetable");
3991  Utilities->CallLogPop(1686);
3992  return;
3993  }
3994  std::ofstream TTBLFile;
3995  if(SaveTTDialog->Execute())
3996  {
3997  CreateEditTTFileName = SaveTTDialog->FileName;
3998  for(int x = SaveTTDialog->FileName.Length(); x > 0; x--)
3999  {
4000  if(SaveTTDialog->FileName[x] == '\\')
4001  {
4002  CreateEditTTTitle = SaveTTDialog->FileName.SubString(x + 1, SaveTTDialog->FileName.Length() - x - 4);
4003  break;
4004  }
4005  }
4006  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
4007  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
4008  }
4009  if(TTBLFile.is_open())
4010  {
4011  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
4012  {
4013  TTBLFile << (*TEVPtr).c_str() << '\0';
4014  }
4015  TimetableChangedFlag = false;
4016  TTBLFile.close();
4017  }
4018  else
4019  {
4020  ShowMessage(CreateEditTTFileName + " failed to open, ensure not already open in another application");
4021  }
4023  SetLevel1Mode(117);
4024  Utilities->CallLogPop(1667);
4025  }
4026  catch(const Exception &e)
4027  {
4028  ErrorLog(108, e.Message);
4029  }
4030 }
4031 // ---------------------------------------------------------------------------
4032 
4033 void __fastcall TInterface::TTServiceSyntaxCheckButtonClick(TObject *Sender)
4034 {
4035  try
4036  {
4037  TrainController->LogEvent("TTServiceSyntaxCheckButtonClick");
4038  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTServiceSyntaxCheckButtonClick");
4039  int Count = 1; // anything > 0 OK as if 0 still seeking a start time
4040  bool EndOfFile = false;
4041  bool FinalCallFalse = false;
4042  bool GiveMessagesTrue = true;
4043  bool CheckLocationsExistInRailway = false;
4044  if(RlyFile)
4045  CheckLocationsExistInRailway = true;
4046 // TrainController->AnyHeadCodeValid = true; //don't fail here because of an unrestricted headcode, if no good will find when validate (dropped at v0.6b)
4047  if(TrainController->ProcessOneTimetableLine(2, Count, *TTCurrentEntryPtr, EndOfFile, FinalCallFalse, GiveMessagesTrue, CheckLocationsExistInRailway))
4048  // return true for success
4049  {
4050  ShowMessage(
4051  "The basic syntax seems OK but this check is very limited. Other aspects can only be checked by validating the whole timetable with the appropriate railway (.rly) loaded");
4052  }
4054  SetLevel1Mode(98);
4055  Utilities->CallLogPop(1624);
4056  }
4057  catch(const Exception &e)
4058  {
4059  ErrorLog(61, e.Message);
4060  }
4061 }
4062 // ---------------------------------------------------------------------------
4063 
4064 void __fastcall TInterface::ValidateTimetableButtonClick(TObject *Sender)
4065 {
4066  try
4067  {
4068  TrainController->LogEvent("ValidateTimetableButtonClick");
4069  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ValidateTimetableButtonClick");
4070  // reset all message flags, stops them being given twice new at v2.4.0
4071  TrainController->SSHigh = false;
4072  TrainController->MRSHigh = false;
4073  TrainController->MRSLow = false;
4074  TrainController->MassHigh = false;
4075  TrainController->BFHigh = false;
4076  TrainController->BFLow = false;
4077  TrainController->PwrHigh = false;
4078  TrainController->SigSHigh = false;
4079  TrainController->SigSLow = false;
4080  if(CreateEditTTFileName == "")
4081  {
4082  Utilities->CallLogPop(1664);
4083  return;
4084  }
4085  bool CheckLocationsExistInRailwayTrue = true;
4086  if(TrainController->TimetableIntegrityCheck(2, CreateEditTTFileName.c_str(), true, CheckLocationsExistInRailwayTrue)) // messages = true
4087  {
4088  Screen->Cursor = TCursor(-11); // Hourglass;
4089  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary);
4090  if(TTBLFile.is_open())
4091  {
4092  if(BuildTrainDataVectorForValidateFile(0, TTBLFile, true, CheckLocationsExistInRailwayTrue)) // messages = true
4093  {
4094  ShowMessage("Timetable integrity OK");
4095  TimetableValidFlag = true;
4096 // TrainController->TrainDataVector.clear(); keep this so can export a formatted tt
4097  };
4098  }
4099  else
4100  {
4101  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
4102  }
4103  Screen->Cursor = TCursor(-2); // Arrow
4104  } // if(TimetableIntegrityCheck
4105  else
4106  {
4107 // ShowMessage("Timetable preliminary integrity check failed"); dropped in v2.4.0 as messages given in all called functions
4108  }
4110  SetLevel1Mode(99);
4111  Utilities->CallLogPop(1625);
4112  }
4113  catch(const Exception &e)
4114  {
4115  ErrorLog(62, e.Message);
4116  }
4117 }
4118 
4119 // ---------------------------------------------------------------------------
4120 void __fastcall TInterface::MoveTTEntryUpButtonClick(TObject *Sender)
4121 {
4122  try
4123  {
4124  TrainController->LogEvent("MoveTTEntryUpButtonClick");
4125  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTTEntryUpButtonClick");
4126  if(TTCurrentEntryPtr == 0)
4127  {
4128  Utilities->CallLogPop(1634);
4129  return;
4130  }
4131  if(TTCurrentEntryPtr < (TimetableEditVector.begin() + 1)) // shouldn't reach here but return if do
4132  {
4133  Utilities->CallLogPop(1632);
4134  return;
4135  }
4136  TEVPtr = TTCurrentEntryPtr - 1; // find earlier Entry
4137  AnsiString TempStr = *TEVPtr;
4139  *TTCurrentEntryPtr = TempStr;
4141  TimetableChangedFlag = true;
4142  TimetableValidFlag = false;
4143 
4144 // now rebuild AllEntriesTTListBox, DisplayOneTTLineInPanel will highlight it
4145  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4146  // position changing in AllEntriesTTListBox
4147  AllEntriesTTListBox->Clear();
4148  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4150 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4151  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4152  {
4154  }
4155  else
4156  {
4157  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4158  }
4160  SetLevel1Mode(100);
4161  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4162  {
4164  }
4165  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4166  {
4167  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4168  }
4169  else
4170  {
4171  AllEntriesTTListBox->TopIndex = TopPos;
4172  }
4173  Utilities->CallLogPop(1626);
4174  }
4175  catch(const Exception &e)
4176  {
4177  ErrorLog(63, e.Message);
4178  }
4179 }
4180 // ---------------------------------------------------------------------------
4181 
4182 void __fastcall TInterface::MoveTTEntryDownButtonClick(TObject *Sender)
4183 {
4184  try
4185  {
4186  TrainController->LogEvent("MoveTTEntryDownButtonClick");
4187  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTTEntryDownButtonClick");
4188  if(TTCurrentEntryPtr == 0)
4189  {
4190  Utilities->CallLogPop(1635);
4191  return;
4192  }
4193  if(TTCurrentEntryPtr >= (TimetableEditVector.end() - 1)) // shouldn't reach here but return if do
4194  {
4195  Utilities->CallLogPop(1678);
4196  return;
4197  }
4198  TEVPtr = TTCurrentEntryPtr + 1; // find later Entry
4199  AnsiString TempStr = *TEVPtr;
4201  *TTCurrentEntryPtr = TempStr;
4203  TimetableChangedFlag = true;
4204  TimetableValidFlag = false;
4205 
4206 // now rebuild AllEntriesTTListBox, DisplayOneTTLineInPanel will highlight it
4207  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4208  // position changing in AllEntriesTTListBox
4209  AllEntriesTTListBox->Clear();
4210  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4212 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4213  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4214  {
4216  }
4217  else
4218  {
4219  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4220  }
4222  SetLevel1Mode(101);
4223  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4224  {
4226  }
4227  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4228  {
4229  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4230  }
4231  else
4232  {
4233  AllEntriesTTListBox->TopIndex = TopPos;
4234  }
4235  Utilities->CallLogPop(1627);
4236  }
4237  catch(const Exception &e)
4238  {
4239  ErrorLog(64, e.Message);
4240  }
4241 }
4242 
4243 // ---------------------------------------------------------------------------
4244 void __fastcall TInterface::CancelTTEntryButtonClick(TObject *Sender)
4245 {
4246  try
4247  {
4248  TrainController->LogEvent("CancelTTActionButtonClick");
4249  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CancelTTActionButtonClick");
4250  TTEntryChangedFlag = false;
4252  {
4253  NewEntryInPreparationFlag = false;
4254  OneEntryTimetableMemo->Clear();
4255  }
4256  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4257  // position changing in AllEntriesTTListBox
4259  SetLevel1Mode(102);
4260  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4261  {
4263  }
4264  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4265  {
4266  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4267  }
4268  else
4269  {
4270  AllEntriesTTListBox->TopIndex = TopPos;
4271  }
4272  Utilities->CallLogPop(1630);
4273  }
4274  catch(const Exception &e)
4275  {
4276  ErrorLog(102, e.Message);
4277  }
4278 }
4279 
4280 // ---------------------------------------------------------------------------
4281 void __fastcall TInterface::RestoreTTButtonClick(TObject *Sender)
4282 {
4283  try
4284  {
4285  TrainController->LogEvent("RestoreTTButtonClick");
4286  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RestoreTTButtonClick");
4288  {
4289  UnicodeString MessageStr = "All changes to the timetable will be lost - proceed?";
4290  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
4291  if(button == IDNO)
4292  {
4293  Utilities->CallLogPop(1651);
4294  return;
4295  }
4296  }
4297 
4298  // repeat from EditTimetableMenuItemClick, but no need to check for non-ascii characters
4299  // open in binary mode so the "\r\n" pairs stay as they are rather than being entered as '\n'
4300  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary);
4301  if(TTBLFile.is_open())
4302  {
4303  TimetableChangedFlag = false;
4304  TimetableValidFlag = false;
4305  TTEntryChangedFlag = false;
4306  NewEntryInPreparationFlag = false;
4307  CopiedEntryFlag = false;
4308  CopiedEntryStr = "";
4309  TimetableEditVector.clear();
4310  OneEntryTimetableMemo->Clear();
4311  AllEntriesTTListBox->Clear();
4312  TTStartTimeBox->Text = "";
4313  AddSubMinsBox->Text = "";
4314  TEVPtr = 0;
4316  TTFirstServicePtr = 0;
4317  TTLastServicePtr = 0; // all set to null to begin with
4318  char *TimetableEntryString = new char[10000];
4319  while(true)
4320  {
4321  TTBLFile.getline(TimetableEntryString, 10000, '\0'); // pick up the entire AnsiString, including any embedded newlines
4322  if(TTBLFile.eof() && (TimetableEntryString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
4323  { // may still have eof even if read a line, and
4324  // if so need to process it
4325  break;
4326  }
4327  AnsiString OneLine(TimetableEntryString);
4328  TimetableEditVector.push_back(OneLine);
4329  }
4330  TTBLFile.close();
4331  delete TimetableEntryString;
4332  // here with TimetableEditVector compiled
4333  }
4334  else
4335  {
4336  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
4337  Utilities->CallLogPop(1655);
4338  return;
4339  }
4340 
4342  if(TimetableEditVector.empty())
4343  {
4345  SetLevel1Mode(114);
4346  Utilities->CallLogPop(1782);
4347  return;
4348  }
4349 // all now set where can be
4351 // end of repeat from EditTimetableMenuItemClick
4352 
4354  SetLevel1Mode(104);
4355  Utilities->CallLogPop(1652);
4356  }
4357  catch(const Exception &e)
4358  {
4359  ErrorLog(104, e.Message);
4360  }
4361 }
4362 
4363 // ---------------------------------------------------------------------------
4364 void __fastcall TInterface::ExportTTButtonClick(TObject *Sender)
4365 {
4366  try
4367  {
4368  TrainController->LogEvent("ExportTTButtonClick");
4369  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExportTTButtonClick");
4370  if(!DirectoryExists(CurDir + "\\" + FORMATTEDTT_DIR_NAME))
4371  {
4372  ShowMessage("Failed to find folder " + FORMATTEDTT_DIR_NAME + " in the folder where 'railway.exe' resides. Timetable can't be exported");
4373  Utilities->CallLogPop(1698);
4374  return;
4375  }
4376  Screen->Cursor = TCursor(-11); // Hourglass;
4377  AnsiString TTTitle;
4379  {
4380  for(int x = CreateEditTTFileName.Length(); x > 0; x--) // first need to strip out the timetable title from the full name
4381  {
4382  if(CreateEditTTFileName[x] == '\\')
4383  {
4384  TTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
4385  break;
4386  }
4387  }
4389  }
4390  Screen->Cursor = TCursor(-2); // Arrow
4392  SetLevel1Mode(116);
4393  Utilities->CallLogPop(1662);
4394  }
4395  catch(const Exception &e)
4396  {
4397  ErrorLog(107, e.Message);
4398  }
4399 }
4400 
4401 // ---------------------------------------------------------------------------
4402 void __fastcall TInterface::TTTextButtonClick(TObject *Sender)
4403 {
4404  try
4405  {
4406  TrainController->LogEvent("TTTextButtonClick");
4407  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTTextButtonClick");
4408 /*
4409  if(TTStartTimePtr == 0)
4410  {
4411  OneEntryTimetableMemo->Clear();
4412  TTStartTimeBox->SetFocus();
4413  Utilities->CallLogPop(1673);
4414  return;
4415  }
4416 */
4417  int SelPos = OneEntryTimetableMemo->SelStart;
4418  AnsiString FirstPart = OneEntryTimetableMemo->Text.SubString(1, SelPos);
4419  AnsiString LastPart = OneEntryTimetableMemo->Text.SubString(SelPos + 1, OneEntryTimetableMemo->Text.Length() - SelPos);
4420  OneEntryTimetableMemo->Text = FirstPart + ((TButton*)Sender)->Caption + LastPart;
4421  OneEntryTimetableMemo->SelStart = SelPos + ((TButton*)Sender)->Caption.Length();
4422  TTEntryChangedFlag = true;
4423  OneEntryTimetableMemo->SetFocus();
4425  SetLevel1Mode(119);
4426  Utilities->CallLogPop(1672);
4427  }
4428  catch(const Exception &e)
4429  {
4430  ErrorLog(110, e.Message);
4431  }
4432 }
4433 
4434 // ---------------------------------------------------------------------------
4435 void __fastcall TInterface::ExitTTModeButtonClick(TObject *Sender)
4436 {
4437  try
4438  {
4439  TrainController->LogEvent("ExitTTCreateEditButtonClick");
4440  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitTTCreateEditButtonClick");
4442  {
4443  UnicodeString MessageStr = "The timetable has changed.\n\nAre you sure you want to exit without saving it?";
4444  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
4445  if(button == IDNO)
4446  {
4447  Utilities->CallLogPop(1603);
4448  return;
4449  }
4450  }
4451  TimetableChangedFlag = false;
4452  CreateEditTTFileName = ""; // set to null to allow a check during error file saving, if not null save the tt being edited to the file
4453  // added for Beta v0.2b
4454  CreateEditTTTitle = ""; // as above
4455  Level1Mode = BaseMode;
4456  SetLevel1Mode(84);
4457  Utilities->CallLogPop(1606);
4458  }
4459  catch(const Exception &e)
4460  {
4461  ErrorLog(49, e.Message);
4462  }
4463 }
4464 
4465 // ---------------------------------------------------------------------------
4466 void __fastcall TInterface::LocationNameComboBoxClick(TObject *Sender)
4467 {
4468  try
4469  {
4470  TrainController->LogEvent("LocationNameComboBoxClick");
4471  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameComboBoxClick");
4472  if(TTStartTimePtr != 0)
4473  {
4474  LocationNameComboBox->SelectAll();
4475  int SelPos = OneEntryTimetableMemo->SelStart;
4476  AnsiString FirstPart = OneEntryTimetableMemo->Text.SubString(1, SelPos);
4477  AnsiString LastPart = OneEntryTimetableMemo->Text.SubString(SelPos + 1, OneEntryTimetableMemo->Text.Length() - SelPos);
4478  OneEntryTimetableMemo->Text = FirstPart + LocationNameComboBox->SelText + LastPart;
4479  OneEntryTimetableMemo->SelStart = SelPos + LocationNameComboBox->SelText.Length();
4480  TTEntryChangedFlag = true;
4481  OneEntryTimetableMemo->SetFocus();
4483  SetLevel1Mode(118);
4484  }
4485  Utilities->CallLogPop(1669);
4486  }
4487  catch(const Exception &e)
4488  {
4489  ErrorLog(109, e.Message);
4490  }
4491 }
4492 
4493 // ---------------------------------------------------------------------------
4494 void __fastcall TInterface::OneEntryTimetableMemoKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4495 {
4496  try
4497  {
4498 // TrainController->LogEvent("OneEntryTimetableMemoKeyUp"); drop this - too many entries
4499  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OneEntryTimetableMemoKeyUp");
4501  {
4502  Utilities->CallLogPop(1716);
4503  return;
4504  }
4505  TimetableChangedFlag = true;
4506  TTEntryChangedFlag = true;
4507  TimetableValidFlag = false;
4509  SetLevel1Mode(127);
4510  Utilities->CallLogPop(1629);
4511  }
4512  catch(const Exception &e)
4513  {
4514  ErrorLog(66, e.Message);
4515  }
4516 }
4517 
4518 // ---------------------------------------------------------------------------
4519 void __fastcall TInterface::AddSubMinsBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4520 {
4521 // forces a recheck for whether addmins/submins buttons should be enabled
4522  try
4523  {
4524  TrainController->LogEvent("AddSubMinsBoxKeyUp");
4525  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddSubMinsBoxKeyUp");
4527  SetLevel1Mode(108);
4528  Utilities->CallLogPop(1658);
4529  }
4530  catch(const Exception &e)
4531  {
4532  ErrorLog(106, e.Message);
4533  }
4534 }
4535 
4536 // ---------------------------------------------------------------------------
4537 void __fastcall TInterface::LocationNameComboBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4538 {
4539  try
4540  {
4541  TrainController->LogEvent("LocationNameComboBoxKeyUp");
4542  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameComboBoxKeyUp");
4543  if(!Track->LocationNameMultiMap.empty())
4544  {
4545  LocationNameComboBox->Text = "Location names";
4546  }
4547  else
4548  {
4549  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
4550  }
4551  Utilities->CallLogPop(1677);
4552  }
4553  catch(const Exception &e)
4554  {
4555  ErrorLog(112, e.Message);
4556  }
4557 }
4558 
4559 // ---------------------------------------------------------------------------
4560 void __fastcall TInterface::AllEntriesTTListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
4561 {
4562 // Select the item pointed to unless a 'save entry' is pending in which case ignore
4563  try
4564  {
4565  TrainController->LogEvent("AllEntriesTTListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4566  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AllEntriesTTListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4567  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
4568  {
4569  Utilities->CallLogPop(1687);
4570  return;
4571  }
4572  if(TTEntryChangedFlag || NewEntryInPreparationFlag) // if a save/cancel pending don't permit anything else
4573  {
4574  Utilities->CallLogPop(1688);
4575  return;
4576  }
4577  // find item required - 13 pixels per line of text
4578  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4579  // position changing in AllEntriesTTListBox
4580  if((TopPos + (Y / 13)) >= AllEntriesTTListBox->Items->Count)
4581  {
4583  }
4584  else
4585  {
4586  TTCurrentEntryPtr = TimetableEditVector.begin() + (Y / 13) + TopPos;
4587  }
4588  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4590 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4591  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4592  {
4594  }
4595  else
4596  {
4597  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4598  }
4600  SetLevel1Mode(120);
4601  AllEntriesTTListBox->TopIndex = TopPos; // reset it after SetLevel1Mode to prevent the scroll position changing
4602  Utilities->CallLogPop(1648);
4603  }
4604  catch(const Exception &e)
4605  {
4606  ErrorLog(103, e.Message);
4607  }
4608 }
4609 // ---------------------------------------------------------------------------
4610 
4611 void __fastcall TInterface::OAListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
4612 {
4613 // Mouseup rather than Mousedown so shows floating label when over train
4614  try
4615  {
4616  TrainController->LogEvent("OAListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4617  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OAListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4618  if(Track->RouteFlashFlag || Track->PointFlashFlag) // no action
4619  {
4620  Utilities->CallLogPop(2087);
4621  return;
4622  }
4624  {
4625  Utilities->CallLogPop(2088);
4626  return;
4627  }
4629  // find item required - 13 pixels per line of text
4630  int TopPos = OAListBox->TopIndex;
4631  int OAIndex;
4632  if((TopPos + (Y / 13)) >= OAListBox->Items->Count) // if click beyond end of list ignore
4633  {
4634  Utilities->CallLogPop(2089);
4635  return;
4636  }
4637  else
4638  {
4639  OACurrentEntryPtr = TrainController->OpTimeToActMultiMap.begin();
4640  std::advance(OACurrentEntryPtr, ((Y / 13) + TopPos));
4641  }
4642  int HPos;
4643  int VPos;
4644  int TrackVectorPosition;
4645  int TrainIDorTVPos = OACurrentEntryPtr->second.second;
4646  if(TrainIDorTVPos >= 0) // running train, so value is the TrainID
4647  {
4648  if(TrainController->TrainExistsAtIdent(0, TrainIDorTVPos)) // added at v2.4.0 in case train removed but still in OA list as not updated yet
4649  // see LiWinDom error report on Discord 23/04/20. Also needed for click OAListBox before any trains show,
4650  // as notified by Rokas Serys by email on 16/05/20
4651  {
4652  TrackVectorPosition = TrainController->TrainVectorAtIdent(43, TrainIDorTVPos).LeadElement;
4653  }
4654  else
4655  {
4656  Utilities->CallLogPop(2155); // if not there then ignore
4657  return;
4658  }
4659  }
4660  else // train to enter at a continuation, so value is -TVPos of continuation - 1
4661  {
4662  TrackVectorPosition = -(TrainIDorTVPos + 1);
4663  }
4664  HPos = (Track->TrackElementAt(926, TrackVectorPosition).HLoc * 16);
4665  VPos = (Track->TrackElementAt(927, TrackVectorPosition).VLoc * 16);
4666  // now want to set the offsets to display HPos & VPos in the centre of the screen
4667  Display->DisplayOffsetH = (HPos - MainScreen->Width / 2) / 16; // ScreenPosH = HPos - (DisplayOffsetH * 16)
4668  Display->DisplayOffsetV = (VPos - MainScreen->Height / 2) / 16;
4669  int ScreenPosH = HPos - (Display->DisplayOffsetH * 16);
4670  int ScreenPosV = VPos - (Display->DisplayOffsetV * 16);
4671  if(Display->ZoomOutFlag) // panel displays in either zoom mode
4672  {
4673  Display->ZoomOutFlag = false;
4675  }
4676  ClearandRebuildRailway(72); // if was zoomed out this displays the track because until ZoomOutFlag reset PlotOutput plots nothing
4677  TPoint MainScreenPoint(ScreenPosH + 8, ScreenPosV + 8); // new v2.2.0 add 8 to centre pointer in element
4678  TPoint CursPos = MainScreen->ClientToScreen(MainScreenPoint); // accurate funtion to convert from local to global co-ordinates
4679  Mouse->CursorPos = CursPos;
4680  Utilities->CallLogPop(2090);
4681  }
4682  catch(const Exception &e)
4683  {
4684  ErrorLog(200, e.Message);
4685  }
4686 }
4687 
4688 // ---------------------------------------------------------------------------
4689 
4691 {
4692  enum
4693  {
4694  PreStartTime, ActiveSegment, PostEnd} Segment;
4695  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CompileAllEntriesMemoAndSetPointers");
4696  AllEntriesTTListBox->Clear();
4697  TEVPtr = 0;
4698  TTStartTimePtr = 0;
4699  TTFirstServicePtr = 0;
4700  TTLastServicePtr = 0; // all set to null to begin with
4701  if(TimetableEditVector.empty())
4702  {
4703  TTCurrentEntryPtr = 0;
4704  Utilities->CallLogPop(1681);
4705  return;
4706  }
4707  Segment = PreStartTime;
4708  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
4709  {
4710  if(Segment == PreStartTime) // looking for the start time
4711  {
4712  TDateTime TempTime; // dummy
4713  if(TrainController->CheckTimeValidity(33, *TEVPtr, TempTime))
4714  {
4715  TTStartTimePtr = TEVPtr; // TTStartTimeBox text set in TTHandler
4716  AllEntriesTTListBox->Items->Add("START " + (*TEVPtr).SubString(1, 5));
4717  Segment = ActiveSegment;
4718  continue;
4719  }
4720  else
4721  {
4722  if(*TEVPtr == "")
4723  {
4724  AllEntriesTTListBox->Items->Add("- Blank");
4725  }
4726  else
4727  {
4728  AnsiString CurrentStr = *TEVPtr;
4729  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
4730  {
4731  CurrentStr = CurrentStr.SubString(1, 10); // limit length for LH window
4732  for(int x = 1; x < CurrentStr.Length(); x++)
4733  {
4734  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
4735  {
4736  CurrentStr = CurrentStr.SubString(1, (x - 1));
4737  }
4738  }
4739  }
4740  AllEntriesTTListBox->Items->Add("- " + CurrentStr);
4741  }
4742  continue;
4743  }
4744  }
4745  if(Segment == ActiveSegment)
4746  {
4747  if(*TEVPtr != "")
4748  {
4749  if((*TEVPtr)[1] != '*')
4750  {
4752  ConvertCRLFsToCommas(0, *TEVPtr); // This needed because an entry intended as a service might have skipped the conversion in
4753  // SaveTTEntryButtonClick - see comment in that function
4754  if(TTFirstServicePtr == 0)
4755  {
4757  }
4759  }
4760  AnsiString Entry = *TEVPtr;
4761  if(Entry[1] == '*')
4762  Entry = "Comment";
4763  else
4764  {
4765  int SCPos = Entry.Pos(';'); // semicolon
4766  int CPos = Entry.Pos(','); // comma
4767  // 5 possibilities: no comma & no semicolon - just text - enter 1st 12 characters
4768  // both, comma before semicolon, i.e text on its own line, semicolon on next line - e.g. service headcode but no
4769  // description - enter the text up to the comma
4770  // both, semicolon before comma, normal - enter text up to the semicolon
4771  // comma & no semicolon, one or more lines of text without any semicolons - enter the text up to the comma
4772  // semicolon & no comma - enter text up to the semicolon
4773  if((CPos == 0) && (SCPos == 0))
4774  {
4775  Entry = Entry.SubString(1, 12);
4776  }
4777  else if((CPos > 0) && (SCPos > 0) && (CPos < SCPos))
4778  {
4779  Entry = Entry.SubString(1, CPos - 1);
4780  }
4781  else if((CPos > 0) && (SCPos > 0) && (CPos > SCPos))
4782  {
4783  Entry = Entry.SubString(1, SCPos - 1);
4784  }
4785  else if((CPos > 0) && (SCPos == 0))
4786  {
4787  Entry = Entry.SubString(1, CPos - 1);
4788  }
4789  else
4790  {
4791  Entry = Entry.SubString(1, SCPos - 1);
4792  }
4793  }
4794  AllEntriesTTListBox->Items->Add(Entry);
4795  continue;
4796  }
4797  else
4798  {
4799  Segment = PostEnd;
4800  AllEntriesTTListBox->Items->Add("END (Blank)");
4801  continue;
4802  }
4803  }
4804  if(Segment == PostEnd)
4805  {
4806  if(*TEVPtr == "")
4807  {
4808  AllEntriesTTListBox->Items->Add("+ Blank");
4809  }
4810  else
4811  {
4812  AnsiString CurrentStr = *TEVPtr;
4813  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
4814  {
4815  CurrentStr = CurrentStr.SubString(1, 10);
4816  for(int x = 1; x < CurrentStr.Length(); x++)
4817  {
4818  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
4819  {
4820  CurrentStr = CurrentStr.SubString(1, (x - 1));
4821  }
4822  }
4823  }
4824  AllEntriesTTListBox->Items->Add("+ " + CurrentStr);
4825  }
4826  continue;
4827  }
4828  }
4829  if(TTStartTimePtr == 0)
4830  {
4831  TTStartTimeBox->Text = "";
4832  }
4833  TTCurrentEntryPtr = TTLastServicePtr; // may well be reset outside this function but need to ensure that it has a valid value on exit, even if it's null
4834  Utilities->CallLogPop(1680);
4835 }
4836 // ---------------------------------------------------------------------------
4837 
4838 void __fastcall TInterface::AZOrderButtonClick(TObject *Sender)
4839 {
4840  try
4841  {
4842  if(TimetableEditVector.empty())
4843  {
4844  return; // should be able to access this if it is but keep in for safety
4845  }
4846  TrainController->LogEvent("AZOrderClick");
4847  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AZOrderClick");
4848  if(AZOrderButton->Caption == AnsiString("A-Z Order"))
4849  {
4850  TTEVPtr SortStart, SortEnd;
4851  UnicodeString MessageStr =
4852  "If you wish to preserve the original order don't make any changes whilst in alphabetical order.\n\nIn that case use alphabetical order to find the service required, click it to display it, then revert to the original order where the same service will be displayed and can be changed.";
4853  Application->MessageBox(MessageStr.c_str(), L"Please Note:", MB_OK | MB_ICONWARNING);
4856  SortStart = TimetableEditVector.begin(); // if no start time set sort from beginning
4857  if(TTFirstServicePtr != NULL)
4858  {
4859  SortStart = TTFirstServicePtr;
4860  }
4861  SortEnd = TimetableEditVector.end(); // if no last service set sort to end
4862  if(TTLastServicePtr != NULL)
4863  {
4864  SortEnd = TTLastServicePtr + 1;
4865  }
4866  std::sort(SortStart, SortEnd);
4868  bool CurrentEntryChanged = false;
4869  for(TTimetableEditVector::iterator x = TimetableEditVector.begin(); x < TimetableEditVector.end(); x++)
4870  {
4871  if(TTSelectedEntry == *x)
4872  {
4873  TTCurrentEntryPtr = x;
4874  CurrentEntryChanged = true;
4875  }
4876  }
4877  if(!CurrentEntryChanged)
4878  {
4880  }
4881  AZOrderButton->Caption = AnsiString("Original Order");
4882  AZOrderButton->Hint = AnsiString("Arrange services in original order Toggle with Shift+ Z");
4883  }
4884  else
4885  {
4887  {
4888  UnicodeString MessageStr =
4889  "Reverting to the original order will discard any changes made whilst in alphabetical order.\n\nTo preserve the changes click 'No', then save the timetable or use 'save as' if you wish to keep the original timetable.\n\nDo you wish to proceed?";
4890  int button = Application->MessageBox(MessageStr.c_str(), L"Warning!", MB_YESNO | MB_ICONWARNING);
4891  if(button == IDNO)
4892  {
4893  TimetableChangedFlag = true;
4894  TimetableValidFlag = false;
4896  SetLevel1Mode(135);
4897  Utilities->CallLogPop(2166);
4898  return;
4899  }
4900  }
4904  bool CurrentEntryChanged = false;
4905  for(TTimetableEditVector::iterator x = TimetableEditVector.begin(); x < TimetableEditVector.end(); x++)
4906  {
4907  if(TTSelectedEntry == *x)
4908  {
4909  TTCurrentEntryPtr = x;
4910  CurrentEntryChanged = true;
4911  }
4912  }
4913  if(!CurrentEntryChanged)
4914  {
4916  }
4917  AZOrderButton->Caption = AnsiString("A-Z Order");
4918  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
4919  }
4920  TimetableChangedFlag = true;
4921  TimetableValidFlag = false;
4924  SetLevel1Mode(136);
4925  Utilities->CallLogPop(2165);
4926  }
4927  catch(const Exception &e)
4928  {
4929  ErrorLog(211, e.Message);
4930  }
4931 }
4932 
4933 // ---------------------------------------------------------------------------
4934 
4935 void TInterface::ConvertCRLFsToCommas(int Caller, AnsiString &ConvStr)
4936 {
4937  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertCRLFsToCommas," + ConvStr);
4938  AnsiString OutStr = "";
4939  int x = 1; // AnsiString arrays start at 1
4940 
4941  while(x < ConvStr.Length()) // skip the last character as looking for CRLF pairs, i.e. '\r' followed by '\n'
4942  {
4943  if((ConvStr[x] == '\r') && (ConvStr[x + 1] == '\n'))
4944  {
4945  OutStr += ',';
4946  x++;
4947  x++;
4948  }
4949  else
4950  {
4951  OutStr += ConvStr[x];
4952  x++;
4953  }
4954  }
4955  if(x == ConvStr.Length())
4956  OutStr += ConvStr[x]; // add the last character
4957 
4958 // strip any excess commas from the end
4959  if(OutStr != "")
4960  {
4961  while(OutStr[OutStr.Length()] == ',')
4962  {
4963  OutStr = OutStr.SubString(1, OutStr.Length() - 1);
4964  if(OutStr == "")
4965  break; // if consisted of just commas then without this would fail on range error when becomes a null string
4966  }
4967  }
4968  ConvStr = OutStr;
4969  if(ConvStr == "")
4970  ConvStr = ','; // don't return a null or will fail, OK to return a comma on its own as will be ignored during ProcessOneTimetableLine
4971  // when AllCommas will be true
4972  Utilities->CallLogPop(1846);
4973 }
4974 
4975 // ---------------------------------------------------------------------------
4976 
4978 {
4979 /* CreateEditTTFileName set if a TT file loaded (even if empty), the pointers TTStartTimePtr, TTFirstServicePtr, TTLastServicePtr provide
4980  relevant information - if null then not set. TTCurrentEntryPtr is set to the Entry to be displayed or null if there's no start time or no
4981  entries
4982 */
4983  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TimetableHandler");
4984  PreviousTTEntryButton->Enabled = false;
4985  NextTTEntryButton->Enabled = false;
4986  AddMinsButton->Enabled = false;
4987  SubMinsButton->Enabled = false;
4988  CopyTTEntryButton->Enabled = false;
4989  CutTTEntryButton->Enabled = false;
4990  PasteTTEntryButton->Enabled = false;
4991  DeleteTTEntryButton->Enabled = false;
4992  SaveTTEntryButton->Enabled = false;
4993  SaveTTButton->Enabled = false;
4994  SaveTTAsButton->Enabled = false;
4995  ValidateTimetableButton->Enabled = false;
4996  AZOrderButton->Enabled = false;
4997  TTServiceSyntaxCheckButton->Enabled = false;
4998  NewTTEntryButton->Enabled = false;
4999  MoveTTEntryUpButton->Enabled = false;
5000  MoveTTEntryDownButton->Enabled = false;
5001  CancelTTEntryButton->Enabled = false;
5002  RestoreTTButton->Enabled = false;
5003  ExportTTButton->Enabled = false;
5004  ExitTTModeButton->Enabled = true;
5005 
5007  {
5008  AZOrderButton->Enabled = true;
5009  }
5010 
5012  TimetableValidFlag = false; // should always be the case anyway but include here to be sure
5013 
5014  if(CreateEditTTFileName == "")
5015  {
5016  TimetableNameLabel->Caption = "Creating new timetable: not yet saved";
5017  }
5018  else
5019  {
5020  TimetableNameLabel->Caption = "Editing timetable: " + CreateEditTTTitle;
5021  }
5022 
5023  if(TTStartTimePtr != 0) // Null means start time not yet set
5024  {
5025  TTStartTimeBox->Text = (*TTStartTimePtr).SubString(1, 5); // 1st 5 chars = time if validity check OK
5026  }
5027 // start time now set & displayed
5028 
5030  {
5031  InfoPanel->Visible = true;
5032  InfoPanel->Caption = "Select option or change entry";
5033  if(RailwayTitle != "")
5034  {
5035  ShowHideTTButton->Enabled = true;
5036  }
5037  else
5038  {
5039  ShowHideTTButton->Enabled = false;
5040  }
5041  ExitTTModeButton->Enabled = true;
5042  AllEntriesTTListBox->Enabled = true;
5043  AnsiString AnsiAddSubText(AddSubMinsBox->Text);
5044  if((AnsiAddSubText != "") && AreAnyTimesInCurrentEntry())
5045  {
5046  bool ValidFlag = true;
5047  for(int x = 1; x <= AnsiAddSubText.Length(); x++)
5048  {
5049  if((AnsiAddSubText[x] > '9') || (AnsiAddSubText[x] < '0'))
5050  {
5051  ValidFlag = false;
5052  break;
5053  }
5054  }
5055  if(ValidFlag)
5056  {
5057  if(AnsiAddSubText.ToInt() != 0)
5058  {
5059  AddMinsButton->Enabled = true;
5060  SubMinsButton->Enabled = true;
5061  }
5062  }
5063  }
5065  {
5066  RestoreTTButton->Enabled = true;
5067  }
5069  { // Need !TimetableChangedFlag because the changed TT must be saved before validation - it's the TT file that is checked
5070  // so if it is changed but not saved, the 'correct' file will check OK but the changed TT may well not be valid
5071  ValidateTimetableButton->Enabled = true;
5072  }
5074  {
5075  ExportTTButton->Enabled = true;
5076  }
5077  if(TTCurrentEntryPtr != 0)
5078  {
5079  CopyTTEntryButton->Enabled = true;
5080  CutTTEntryButton->Enabled = true;
5081  DeleteTTEntryButton->Enabled = true;
5082  }
5083  if((TimetableChangedFlag) && !TimetableEditVector.empty())
5084  {
5085  SaveTTButton->Enabled = true;
5086  }
5087  if(!TimetableEditVector.empty())
5088  {
5089  SaveTTAsButton->Enabled = true;
5090  }
5092  {
5093  NewTTEntryButton->Enabled = true;
5094  }
5095  if((TTCurrentEntryPtr > 0) && !TimetableEditVector.empty())
5096  {
5097  if((TimetableEditVector.end() - 1) > TTCurrentEntryPtr)
5098  {
5099  NextTTEntryButton->Enabled = true;
5100  MoveTTEntryDownButton->Enabled = true;
5101  }
5103  {
5104  PreviousTTEntryButton->Enabled = true;
5105  MoveTTEntryUpButton->Enabled = true;
5106  }
5107  }
5108  if(TTCurrentEntryPtr > 0)
5109  {
5110  if(*TTCurrentEntryPtr != "")
5111  {
5113  {
5114  TTServiceSyntaxCheckButton->Enabled = true;
5115  }
5116  }
5117  }
5118  if(CopiedEntryFlag)
5119  {
5120  PasteTTEntryButton->Enabled = true;
5121  }
5122  OneEntryTimetableMemo->Clear(); // don't clear if Entry changed
5123  if(TTCurrentEntryPtr > 0)
5124  {
5125 // if(*TTCurrentEntryPtr != "") leave this out or fails to highlight blank line entries
5127  {
5128  bool ServiceEntry = true;
5129  DisplayOneTTLineInPanel(0, *TTCurrentEntryPtr, ServiceEntry);
5130  }
5131  else
5132  {
5133  bool ServiceEntry = false;
5134  DisplayOneTTLineInPanel(1, *TTCurrentEntryPtr, ServiceEntry);
5135  }
5136  }
5137  }
5138  else
5139  {
5140  CancelTTEntryButton->Enabled = true;
5141  SaveTTEntryButton->Enabled = true;
5142  ShowHideTTButton->Enabled = false;
5143  ExitTTModeButton->Enabled = false;
5144  AllEntriesTTListBox->Enabled = false; // to stop entries being selected
5145  InfoPanel->Caption = "Add or change entry then save it, or cancel";
5146  InfoPanel->Visible = true;
5147  }
5148  Utilities->CallLogPop(1600);
5149 }
5150 
5151 // ---------------------------------------------------------------------------
5152 void TInterface::DisplayOneTTLineInPanel(int Caller, AnsiString Data, bool ServiceEntry)
5153 {
5154  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DisplayOneTTLineInPanel," + Data + ", " +
5155  AnsiString((short)ServiceEntry));
5156  OneEntryTimetableMemo->Clear();
5157  if(ServiceEntry)
5158  {
5159  TrainController->StripSpaces(1, Data);
5160  while(true)
5161  {
5162  int CommaPos = Data.Pos(',');
5163  if((CommaPos == 0) && (Data != ""))
5164  {
5165  CommaPos = Data.Length() + 1;
5166  }
5167  OneEntryTimetableMemo->Lines->Add(Data.SubString(1, CommaPos - 1));
5168  if(Data.Length() <= CommaPos)
5169  break;
5170  Data = Data.SubString(CommaPos + 1, Data.Length() - CommaPos);
5171  }
5172  }
5173  else
5174  {
5175  OneEntryTimetableMemo->Text = Data;
5176  }
5177  int TotalLines = OneEntryTimetableMemo->Lines->Count; // remove excess lines at bottom
5178 
5179  while((OneEntryTimetableMemo->Lines->Strings[TotalLines - 1] == "") || (OneEntryTimetableMemo->Lines->Strings[TotalLines - 1] == "\r\n"))
5180  {
5181  OneEntryTimetableMemo->Lines->Delete(TotalLines - 1);
5182  TotalLines--;
5183  if(TotalLines < 1)
5184  break;
5185  }
5186  OneEntryTimetableMemo->HideSelection = true;
5187  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
5188  OneEntryTimetableMemo->SelLength = 0;
5190  Utilities->CallLogPop(1602);
5191 }
5192 // ---------------------------------------------------------------------------
5193 
5195 {
5196  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",HighlightOneEntryInAllEntriesTTListBox," + AnsiString(Position));
5197  if(TimetableEditVector.empty() || (AllEntriesTTListBox->Items->Count == 0))
5198  {
5199  HighlightPanel->Top = 32;
5200  HighlightPanel->Caption = "";
5201  HighlightPanel->Width = 100;
5202  HighlightPanel->Visible = false;
5203  }
5204  else
5205  {
5206  AnsiString CurrentStr = AllEntriesTTListBox->Items->Strings[Position];
5207  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
5208  {
5209  for(int x = 1; x < CurrentStr.Length(); x++)
5210  {
5211  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
5212  {
5213  CurrentStr = CurrentStr.SubString(1, (x - 1));
5214  }
5215  }
5216  }
5217  HighlightPanel->Top = 32 + (Position * 13) - (AllEntriesTTListBox->TopIndex * 13);
5218  if(HighlightPanel->Top < 32)
5219  HighlightPanel->Visible = false;
5220  else
5221  HighlightPanel->Visible = true; // doesn't matter if goes off the bottom as it becomes invisible as then it's off its parent panel
5222  HighlightPanel->Caption = CurrentStr;
5223  if(AllEntriesTTListBox->Items->Count > 46)
5224  HighlightPanel->Width = 82;
5225  else
5226  HighlightPanel->Width = 100;
5227  }
5228  Utilities->CallLogPop(1709);
5229 }
5230 
5231 // ---------------------------------------------------------------------------
5233 {
5234  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == ""))
5235  {
5236  return false;
5237  }
5238  TDateTime DummyTime;
5239  bool TimesPresent = false;
5240 
5241  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
5242  {
5243  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
5244  {
5245  if(TrainController->CheckTimeValidity(20, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
5246  {
5247  TimesPresent = true;
5248  break;
5249  }
5250  }
5251  if(TimesPresent)
5252  break;
5253  }
5254  return TimesPresent;
5255 }
5256 
5257 // ---------------------------------------------------------------------------
5258 // end of Timetable editing functions
5259 // ---------------------------------------------------------------------------
5260 void __fastcall TInterface::ExitMenuItemClick(TObject *Sender)
5261 {
5262  try
5263  {
5264  TrainController->LogEvent("ExitMenuItemClick");
5265  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitMenuItemClick");
5267  {
5268  UnicodeString MessageStr =
5269  "Note that leaving the track unlinked will cause preferred directions to be lost on reloading. Prevent by linking the track then resaving. Do you still wish to exit?";
5270  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
5271  if(button == IDNO)
5272  {
5273  Utilities->CallLogPop(1711);
5274  return;
5275  }
5276  }
5277  if(FileChangedFlag)
5278  {
5279  UnicodeString MessageStr = "The railway has changed, exit without saving?";
5280  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
5281  if(button == IDNO)
5282  {
5283  Utilities->CallLogPop(1180);
5284  return;
5285  }
5286  }
5287  if((TempTTFileName != "") && FileExists(TempTTFileName))
5288  {
5289  DeleteFile(TempTTFileName);
5290  }
5291  Utilities->CallLogPop(1181);
5292  Application->Terminate();
5293  }
5294  catch(const Exception &e)
5295  {
5296  ErrorLog(140, e.Message);
5297  }
5298 }
5299 // ---------------------------------------------------------------------------
5300 
5301 void __fastcall TInterface::TrackInfoOnOffMenuItemClick(TObject *Sender)
5302 {
5303  try
5304  {
5305  TrainController->LogEvent("TrackInfoOnOffMenuItemClick");
5306  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrackInfoOnOffMenuItemClick");
5307  if(TrackInfoOnOffMenuItem->Caption == "Show")
5308  {
5309  TrackInfoOnOffMenuItem->Caption = "Hide";
5310  }
5311  else
5312  {
5313  TrackInfoOnOffMenuItem->Caption = "Show";
5314  }
5315  Utilities->CallLogPop(1183);
5316  }
5317  catch(const Exception &e)
5318  {
5319  ErrorLog(173, e.Message);
5320  }
5321 }
5322 // ---------------------------------------------------------------------------
5323 
5324 void __fastcall TInterface::TrainStatusInfoOnOffMenuItemClick(TObject *Sender)
5325 {
5326  try
5327  {
5328  TrainController->LogEvent("TrainStatusInfoOnOffMenuItemClick");
5329  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrainStatusInfoOnOffMenuItemClick");
5330  if(TrainStatusInfoOnOffMenuItem->Caption == "Show Status")
5331  {
5332  TrainStatusInfoOnOffMenuItem->Caption = "Hide Status";
5333  }
5334  else
5335  {
5336  TrainStatusInfoOnOffMenuItem->Caption = "Show Status";
5337  }
5338  Utilities->CallLogPop(1184);
5339  }
5340  catch(const Exception &e)
5341  {
5342  ErrorLog(141, e.Message);
5343  }
5344 }
5345 
5346 // ---------------------------------------------------------------------------
5347 void __fastcall TInterface::TrainTTInfoOnOffMenuItemClick(TObject *Sender)
5348 {
5349  try
5350  {
5351  TrainController->LogEvent("TrainTTInfoOnOffMenuItemClick");
5352  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrainTTInfoOnOffMenuItemClick");
5353  if(TrainTTInfoOnOffMenuItem->Caption == "Show Timetable")
5354  {
5355  TrainTTInfoOnOffMenuItem->Caption = "Hide Timetable";
5356  }
5357  else
5358  {
5359  TrainTTInfoOnOffMenuItem->Caption = "Show Timetable";
5360  }
5361  Utilities->CallLogPop(1185);
5362  }
5363  catch(const Exception &e)
5364  {
5365  ErrorLog(142, e.Message);
5366  }
5367 }
5368 
5369 // ---------------------------------------------------------------------------
5370 // Dragging Functions
5371 // ---------------------------------------------------------------------------
5372 void __fastcall TInterface::AcceptDragging(TObject *Sender, TObject *Source, int X, int Y, TDragState State, bool &Accept)
5373 {
5374 // allow in zoom out mode
5375  try
5376  {
5377 // TrainController->LogEvent("AcceptDragging"); drop this, have too many
5378  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AcceptDragging");
5379  if((Source == PerformancePanel) || (Source == PerformancePanelLabel) || (Source == PerformanceLogBox))
5380  {
5381  Accept = true;
5382  int PPLeft = PerformancePanel->Left;
5383  int PPTop = PerformancePanel->Left;
5384 
5385  PPLeft = Mouse->CursorPos.x - PerformancePanelDragStartX;
5386  PPTop = Mouse->CursorPos.y - PerformancePanelDragStartY;
5387  if((PPLeft + PerformancePanel->Width) < 32)
5388  PPLeft = 32 - PerformancePanel->Width;
5389  if(PPLeft > (MainScreen->Left + MainScreen->Width))
5390  PPLeft = MainScreen->Left + MainScreen->Width;
5391  if((PPTop + PerformancePanel->Height) < MainScreen->Top)
5392  PPTop = MainScreen->Top - PerformancePanel->Height;
5393  if(PPTop > (MainScreen->Top + MainScreen->Height - 20))
5394  PPTop = MainScreen->Top + MainScreen->Height - 20;
5395  PerformancePanel->Left = PPLeft;
5396  PerformancePanel->Top = PPTop;
5397  }
5398  else if((Source == OperatorActionPanel) || (Source == OAPanelLabel))
5399  // not the listbox because that used for selecting trains
5400  {
5401  Accept = true;
5402  int OALeft = OperatorActionPanel->Left;
5403  int OATop = OperatorActionPanel->Left;
5404 
5405  OALeft = Mouse->CursorPos.x - OperatorActionPanelDragStartX;
5406  OATop = Mouse->CursorPos.y - OperatorActionPanelDragStartY;
5407  if((OALeft + OperatorActionPanel->Width) < 32)
5408  OALeft = 32 - OperatorActionPanel->Width;
5409  if(OALeft > (MainScreen->Left + MainScreen->Width))
5410  OALeft = MainScreen->Left + MainScreen->Width;
5411  if((OATop + OperatorActionPanel->Height) < MainScreen->Top)
5412  OATop = MainScreen->Top - OperatorActionPanel->Height;
5413  if(OATop > (MainScreen->Top + MainScreen->Height - 20))
5414  OATop = MainScreen->Top + MainScreen->Height - 20;
5415  OperatorActionPanel->Left = OALeft;
5416  OperatorActionPanel->Top = OATop;
5417  }
5418  else
5419  Accept = false;
5420  Utilities->CallLogPop(1186);
5421  }
5422  catch(const Exception &e)
5423  {
5424  ErrorLog(143, e.Message);
5425  }
5426 }
5427 
5428 // ---------------------------------------------------------------------------
5429 void __fastcall TInterface::PerformancePanelStartDrag(TObject *Sender, TDragObject *&DragObject)
5430 {
5431 // allow in zoom out mode
5432  try
5433  {
5434  TrainController->LogEvent("PerformancePanelStartDrag");
5435  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformancePanelStartDrag");
5436  PerformancePanelDragStartX = Mouse->CursorPos.x - PerformancePanel->Left;
5437  PerformancePanelDragStartY = Mouse->CursorPos.y - PerformancePanel->Top;
5438  Utilities->CallLogPop(1187);
5439  }
5440  catch(const Exception &e)
5441  {
5442  ErrorLog(144, e.Message);
5443  }
5444 }
5445 // ---------------------------------------------------------------------------
5446 
5447 void __fastcall TInterface::OperatorActionPanelStartDrag(TObject *Sender, TDragObject *&DragObject) // new v2.2.0
5448 
5449 {
5450 // allow in zoom out mode
5451  try
5452  {
5453  TrainController->LogEvent("OperatorActionPanelStartDrag");
5454  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperatorActionPanelStartDrag");
5455  OperatorActionPanelDragStartX = Mouse->CursorPos.x - OperatorActionPanel->Left;
5456  OperatorActionPanelDragStartY = Mouse->CursorPos.y - OperatorActionPanel->Top;
5457  Utilities->CallLogPop(2091);
5458  }
5459  catch(const Exception &e)
5460  {
5461  ErrorLog(201, e.Message);
5462  }
5463 }
5464 
5465 // ---------------------------------------------------------------------------
5466 // Mouse Functions
5467 // ---------------------------------------------------------------------------
5468 void __fastcall TInterface::MainScreenMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
5469  // caller function - stops master clock
5470 {
5471 // have to allow in zoom out mode
5472  try
5473  {
5474  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseDown," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
5475  bool ClockState = Utilities->Clock2Stopped;
5476  Utilities->Clock2Stopped = true;
5477 
5478  RestoreFocusPanel->Enabled = true; // these added at v2.0.0 to restore navigation keys to move screen when a panel had focus
5479  RestoreFocusPanel->Visible = true; // because then these buttons just cycled through the panel buttons. Added in place of the
5480  RestoreFocusPanel->SetFocus(); // section in ClockTimer2 where focus restored every clock cycle, because then the help screen
5481  RestoreFocusPanel->Visible = false; // was hidden. At least now help is only hidden when the screen clicked, which is normal
5482  RestoreFocusPanel->Enabled = false; // behaviour, and can tell user that can restore navigation keys just by clicking the screen
5483 
5485  {
5486  if(!Display->ZoomOutFlag)
5487  MainScreenMouseDown2(0, Button, Shift, X, Y);
5488  else
5489  MainScreenMouseDown3(0, Button, Shift, X, Y);
5490  }
5491  Utilities->Clock2Stopped = ClockState;
5492  Utilities->CallLogPop(33);
5493  }
5494  catch(const Exception &e)
5495  {
5496  ErrorLog(19, e.Message);
5497  }
5498 }
5499 
5500 // ---------------------------------------------------------------------------
5501 void TInterface::MainScreenMouseDown2(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
5502 {
5503  try
5504  {
5505  TrainController->LogEvent("MainScreenMouseDown2," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
5506  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MainScreenMouseDown2," + AnsiString(Button) + "," + AnsiString(X) +
5507  "," + AnsiString(Y));
5508  // unplot GapFlash graphics if plotted & cancel gap flashing (either key down)
5509  // but not in ZoomOut mode - so can switch between modes & keep gaps flashing
5511  {
5514  Track->GapFlashFlag = false;
5515  }
5516  int HLoc, VLoc;
5517  Track->GetTrackLocsFromScreenPos(1, HLoc, VLoc, X, Y);
5518  int NoOffsetX, NoOffsetY;
5519  Track->GetTruePositionsFromScreenPos(0, NoOffsetX, NoOffsetY, X, Y);
5520  if(Button == mbRight) // track, PrefDir or text erase, PrefDir/route truncate, or take signaller control of train
5521  {
5522  // this routine new at v2.1.0. Allows railway moving for zoom-in mode when no element at HLoc & VLoc
5523  int Dummy; // unused in next function
5524  if(!Track->TrackElementPresentAtHV(0, HLoc, VLoc) && !Track->InactiveTrackElementPresentAtHV(0, HLoc, VLoc) && !Track->UserGraphicPresentAtHV(0, X,
5525  Y, Dummy))
5526  {
5529  WholeRailwayMoving = true;
5530  Screen->Cursor = TCursor(-22); // Four arrows;
5531  }
5532 
5533  else if(Level2TrackMode == AddText)
5534  {
5535  TrainController->LogEvent("mbRight + AddText");
5537  if(TextHandler->TextFound(0, NoOffsetX, NoOffsetY))
5538  {
5539  if(TextHandler->TextErase(0, NoOffsetX, NoOffsetY)) // erase text in vector
5540  {
5542  if(NoRailway())
5543  {
5544  EditMenu->Enabled = false;
5545  }
5546  else
5547  EditMenu->Enabled = true;
5548  }
5549  }
5550  SetLevel2TrackMode(57); // to remove 'move text' if last text item removed
5551  Utilities->CallLogPop(34);
5552  return;
5553  }
5554  else if(Level2TrackMode == AddGraphic)
5555  {
5556  TrainController->LogEvent("mbRight + AddGraphic");
5557  if(Track->UserGraphicVector.empty()) // no user graphics
5558  {
5559  Utilities->CallLogPop(2180);
5560  return;
5561  }
5562  int UGIVecPos;
5563  if(Track->UserGraphicPresentAtHV(1, X, Y, UGIVecPos))
5564  {
5565  Track->UserGraphicVector.erase(Track->UserGraphicVector.begin() + UGIVecPos);
5567  if(NoRailway())
5568  {
5569  EditMenu->Enabled = false;
5570  }
5571  else
5572  EditMenu->Enabled = true;
5573  }
5574  Utilities->CallLogPop(2181);
5575  return;
5576  }
5577 
5578  else if(Level2TrackMode == AddTrack)
5579  {
5580  TrainController->LogEvent("mbRight + AddTrack");
5581  bool TrackEraseSuccessfulFlag;
5582  int ErasedTrackVectorPosition;
5583  Screen->Cursor = TCursor(-11); // Hourglass;
5584  Track->EraseTrackElement(1, HLoc, VLoc, ErasedTrackVectorPosition, TrackEraseSuccessfulFlag, true);
5585  if(TrackEraseSuccessfulFlag)
5586  {
5587  if(ErasedTrackVectorPosition > -1)
5588  EveryPrefDir->RealignAfterTrackErase(0, ErasedTrackVectorPosition);
5591  ClearandRebuildRailway(5); // to ensure location named elements plotted correctly & replot the grid if required
5592  SetGapsButton->Enabled = false; // if conditions have changed need to reset buttons, best not calling SetLevel2TrackMode as that
5593  TrackOKButton->Enabled = false; // calls Clearand.. if gridflag set & takes a long time
5594  if(Track->GapsUnset(1))
5595  {
5596  SetGapsButton->Enabled = true;
5597  }
5598  // only enable if there are gaps still to be set (returns false for no track)
5599  else
5600  {
5601  if(!(Track->NoActiveTrack(0)) && !(Track->IsTrackFinished()))
5602  {
5603  TrackOKButton->Enabled = true;
5604  }
5605  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
5606  }
5607  if(!(Track->IsTrackFinished())) // can only set lengths for several elements together if TrackFinished
5608  {
5609  SetLengthsButton->Enabled = false;
5610  }
5611  if(NoRailway())
5612  {
5613  EditMenu->Enabled = false;
5614  }
5615  else
5616  EditMenu->Enabled = true;
5617  }
5618  Screen->Cursor = TCursor(-2); // Arrow
5619  Utilities->CallLogPop(35);
5620  return;
5621  }
5622  else if(Level2TrackMode == DistanceContinuing) // new for extended distances (similar to PrefDirContinuing)
5623  {
5624  TrainController->LogEvent("mbRight + DistanceContinuing");
5626  bool LeadingPointsAtLastElement = false;
5627  if(ConstructPrefDir->GetPrefDirTruncateElement(0, HLoc, VLoc))
5628  {
5629  if(ConstructPrefDir->PrefDirSize() == 0)
5630  {
5632  SetLevel1Mode(64);
5634  SetLevel2TrackMode(51); // calls ClearandRebuildRailway to show length erased & sets back to start
5635  Utilities->CallLogPop(1526);
5636  return;
5637  }
5640  ConstructPrefDir->CalcDistanceAndSpeed(0, OverallDistance, OverallSpeedLimit, LeadingPointsAtLastElement);
5641  if(!LeadingPointsAtLastElement)
5642  {
5643  TrackLengthPanel->Visible = true;
5644  TrackLengthPanel->SetFocus();
5645  InfoPanel->Visible = true;
5646  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
5647  RestoreAllDefaultLengthsButton->Enabled = true;
5648  ResetDefaultLengthButton->Enabled = true;
5649  LengthOKButton->Enabled = true;
5650  DistanceBox->Text = AnsiString(OverallDistance);
5651  if(OverallSpeedLimit > -1)
5652  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
5653  else
5654  SpeedLimitBox->Text = "Mixed";
5655  }
5656  else
5657  {
5658  TrackLengthPanel->Visible = true;
5659  TrackLengthPanel->SetFocus();
5660  InfoPanel->Visible = true;
5661  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Can't end on leading points, continue or truncate";
5662  RestoreAllDefaultLengthsButton->Enabled = false;
5663  ResetDefaultLengthButton->Enabled = false;
5664  LengthOKButton->Enabled = false;
5665  }
5667  }
5668  Utilities->CallLogPop(36);
5669  return;
5670  }
5671 
5672  else if(Level2PrefDirMode == PrefDirContinuing) // truncate
5673  {
5674  TrainController->LogEvent("mbRight + PrefDirContinuing");
5676 // RlyFile = false; - don't alter this just for PrefDir changes
5677  if(ConstructPrefDir->GetPrefDirTruncateElement(1, HLoc, VLoc))
5678  {
5679  if(ConstructPrefDir->PrefDirSize() == 0)
5680  {
5682  SetLevel1Mode(14); // all PrefDir truncated
5683  Utilities->CallLogPop(37);
5684  return;
5685  }
5687  }
5689  SetLevel2PrefDirMode(0); // calls ClearandRebuildRailway to show length erased & sets back to start
5690  Utilities->CallLogPop(38);
5691  return;
5692  }
5693 
5694  else if((Level1Mode == PrefDirMode) && (Level2PrefDirMode != PrefDirContinuing) && (Level2PrefDirMode != PrefDirSelecting)) // delete element
5695  {
5696  TrainController->LogEvent("mbRight + != PrefDirContinuing");
5698 // RlyFile = false; - don't alter this just for PrefDir changes
5701  SetLevel1Mode(15); // calls ClearandRebuildRailway to show length erased & sets back to start
5702  Utilities->CallLogPop(39);
5703  return;
5704  }
5705 
5706  else if((Level2OperMode == Operating) || (Level2OperMode == PreStart)) // disallow when paused, but allow some parts in prestart
5707  {
5708  TrainController->LogEvent("mbRight + OperMode");
5709  bool FoundFlag;
5710  int VecPos = Track->GetVectorPositionFromTrackMap(1, HLoc, VLoc, FoundFlag);
5711  if(FoundFlag && (Level2OperMode != PreStart)) // disallow signaller control in PreStart
5712  {
5714  // signaller control of train
5715  if(SelectedTrainID > -1)
5716  {
5719  if((Train.LeadElement == -1) || (Track->TrackElementAt(788, Train.LeadElement).Conn[Train.LeadExitPos] == -1))
5720  {
5721  if(Train.TrainMode == Signaller)
5722  {
5724  }
5725  }
5726  if((Train.Stopped()) || (Train.TrainFailed && !(Train.TrainMode == Signaller)) ||
5728  !Train.StepForwardFlag))
5729  // don't allow signaller popup menu in timetable mode unless stopped,
5730  // or when coming to a stop or leaving at a continuation when under signaller control
5731  // or when failed
5732  {
5733  // don't allow selection if another stopped train at a bridge position
5734  if(Track->TrackElementAt(630, VecPos).TrackType == Bridge)
5735  {
5736  int TrainID01 = Track->TrackElementAt(631, VecPos).TrainIDOnBridgeTrackPos01;
5737  int TrainID23 = Track->TrackElementAt(632, VecPos).TrainIDOnBridgeTrackPos23;
5738  if((TrainID01 > -1) && (TrainID23 > -1))
5739  {
5740  TrainController->StopTTClockMessage(0, "Can't select a train at a bridge when another train is at the same bridge");
5741  Utilities->CallLogPop(1103);
5742  return;
5743  }
5744  }
5745  if(Train.TrainMode == Timetable)
5746  {
5747  TakeSignallerControlMenuItem->Enabled = true;
5748  TimetableControlMenuItem->Enabled = false;
5749  ChangeDirectionMenuItem->Enabled = false;
5750  MoveForwardsMenuItem->Enabled = false;
5751  SignallerJoinedByMenuItem->Enabled = false;
5752  RepairFailedTrainMenuItem->Enabled = false;
5753  StepForwardMenuItem->Enabled = false;
5754  RemoveTrainMenuItem->Enabled = false;
5755  PassRedSignalMenuItem->Enabled = false;
5756  SignallerControlStopMenuItem->Enabled = false;
5757  }
5758  else // signaller mode
5759  {
5760  TakeSignallerControlMenuItem->Enabled = false;
5761  if((Train.Crashed) || (Train.Derailed))
5762  {
5763  TimetableControlMenuItem->Enabled = false;
5764  ChangeDirectionMenuItem->Enabled = false;
5765  MoveForwardsMenuItem->Enabled = false;
5766  SignallerJoinedByMenuItem->Enabled = false;
5767  RepairFailedTrainMenuItem->Enabled = false;
5768  StepForwardMenuItem->Enabled = false;
5769  PassRedSignalMenuItem->Enabled = false;
5770  SignallerControlStopMenuItem->Enabled = false;
5771  RemoveTrainMenuItem->Enabled = true;
5772  }
5773  else if(Train.Stopped())
5774  {
5775  if(Train.TimetableFinished)
5776  {
5777  TimetableControlMenuItem->Enabled = false;
5778  }
5779  else
5780  {
5781  if(Train.RestoreTimetableLocation == "") // en route
5782  {
5783  TimetableControlMenuItem->Enabled = true;
5784  }
5785  else
5786  {
5787  // obtain train location & check if OK for restoration of tt control
5788  AnsiString LocName = "";
5789  if(Train.LeadElement > -1)
5790  {
5791  LocName = Track->TrackElementAt(802, Train.LeadElement).ActiveTrackElementName;
5792  }
5793  if((LocName == "") && (Train.MidElement > -1))
5794  {
5795  LocName = Track->TrackElementAt(803, Train.MidElement).ActiveTrackElementName;
5796  }
5797  if(Train.RestoreTimetableLocation == LocName)
5798  {
5799  TimetableControlMenuItem->Enabled = true;
5800  }
5801  else
5802  {
5803  TimetableControlMenuItem->Enabled = false;
5804  }
5805  }
5806  }
5807 // don't allow ChangeDirection if lead or mid elements (but not lag or next) -1, or lead, mid, lag or next elements continuations
5808  ChangeDirectionMenuItem->Enabled = true;
5809  if(Train.LeadElement > -1)
5810  {
5812  {
5813  ChangeDirectionMenuItem->Enabled = false;
5814  }
5815  if(Track->TrackElementAt(791, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
5816  {
5817  if(Track->TrackElementAt(792, (Track->TrackElementAt(793, Train.LeadElement).Conn[Train.LeadExitPos]))
5818  .TrackType == Continuation)
5819  {
5820  ChangeDirectionMenuItem->Enabled = false;
5821  }
5822  }
5823  }
5824  else
5825  ChangeDirectionMenuItem->Enabled = false;
5826  if(Train.MidElement > -1)
5827  {
5829  {
5830  ChangeDirectionMenuItem->Enabled = false;
5831  }
5832  }
5833  else
5834  ChangeDirectionMenuItem->Enabled = false;
5835  if(Train.LagElement > -1)
5836  {
5838  {
5839  ChangeDirectionMenuItem->Enabled = false;
5840  }
5841  }
5842  RemoveTrainMenuItem->Enabled = true;
5843  SignallerControlStopMenuItem->Enabled = false;
5844  SignallerJoinedByMenuItem->Enabled = false;
5845  RepairFailedTrainMenuItem->Enabled = false;
5846  StepForwardMenuItem->Enabled = false;
5847  MoveForwardsMenuItem->Enabled = false;
5848  PassRedSignalMenuItem->Enabled = false;
5849  if(Train.AbleToMove(0))
5850  {
5851  MoveForwardsMenuItem->Enabled = true;
5853  StepForwardMenuItem->Enabled = true; // added 'if' condition for v1.3.2 due to Carwyn Thomas error,
5854  } // fails on trying to calc AutoSig time delay for resetting signals
5855  if(Train.AbleToMoveButForSignal(0)) // may not be in AutoSigs route but disallow anyway as not needed at continuation
5856  {
5857  PassRedSignalMenuItem->Enabled = true;
5858  StepForwardMenuItem->Enabled = true;
5859  }
5860  TTrain *AdjacentTrain;
5861  if(Train.IsThereAnAdjacentTrain(0, AdjacentTrain))
5862  {
5863  SignallerJoinedByMenuItem->Enabled = true;
5864  }
5865  if(Train.TrainFailed)
5866  {
5867  RepairFailedTrainMenuItem->Enabled = true;
5868  }
5869  }
5870  else // train moving under signaller control - only permit restoration of TT control when stopped as could be in
5871  // mid move, & SetTrainMovementValues only intended to be called when stopped
5872  {
5873  TimetableControlMenuItem->Enabled = false;
5874  ChangeDirectionMenuItem->Enabled = false;
5875  RemoveTrainMenuItem->Enabled = false;
5876  MoveForwardsMenuItem->Enabled = false;
5877  SignallerJoinedByMenuItem->Enabled = false;
5878  RepairFailedTrainMenuItem->Enabled = false;
5879  PassRedSignalMenuItem->Enabled = false;
5880  StepForwardMenuItem->Enabled = false;
5881  SignallerControlStopMenuItem->Enabled = true;
5882  }
5883  }
5884  TrainHeadCodeMenuItem->Caption = Train.HeadCode + ":";
5885  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
5887  PopupMenu->Popup(X, Y); // menu stops everything so reset timetable time when restarts
5888  TrainController->BaseTime = TDateTime::CurrentDateTime();
5890  Utilities->CallLogPop(40);
5891  return;
5892  }
5893  }
5894  }
5895 
5896  if(RouteMode == RouteContinuing) // clear a single element (clears whether use left or right mouse button) +allow in PreStart
5897  {
5898  TrainController->LogEvent("mbRight + RouteContinuing");
5900  Utilities->CallLogPop(41);
5901  return;
5902  }
5903 
5904  else if(RouteCancelFlag) // allow in PreStart
5905  {
5906  TrainController->LogEvent("mbRight + RouteCancelFlag");
5907  Screen->Cursor = TCursor(-11); // Hourglass;
5908  // stop clock as sometimes takes several seconds
5909  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
5911  if(AllRoutes->GetAllRoutesTruncateElement(0, HLoc, VLoc, ConsecSignalsRoute)) // updates LockedRouteClass
5912  {
5913  ClearandRebuildRailway(6); // to replot new shorter route
5914  }
5916  TrainController->BaseTime = TDateTime::CurrentDateTime();
5918  Screen->Cursor = TCursor(-2); // Arrow
5919  }
5920 
5921  else // gap flashing, don't allow to interfere with RouteCancelFlag
5922  {
5923  TrainController->LogEvent("mbRight, GapFlashingInOperOrPreStartMode");
5924  int Position;
5925  TTrackElement TrackElement;
5926  if(Track->FindNonPlatformMatch(4, HLoc, VLoc, Position, TrackElement));
5927  {
5928  if((TrackElement.TrackType == GapJump) && (TrackElement.Conn[0] > -1))
5929  {
5930  if((TrackElement.TrainIDOnElement == -1) && (Track->TrackElementAt(818, TrackElement.Conn[0]).TrainIDOnElement == -1))
5931  { // don't flash if train on either gap element
5932  Track->GapFlashGreenPosition = TrackElement.Conn[0];
5937  Track->GapFlashRedPosition = Position;
5942  Track->GapFlashFlag = true;
5943  }
5944  }
5945  }
5946  Utilities->CallLogPop(42);
5947  return; // covers above else & included here in case any more usermodes added later
5948  }
5949  }
5950 
5951  // deal with gap selection - if no other right button selection - apply for any mode (also included in OperMode above)
5952  TrainController->LogEvent("mbRight, GapFlashingNotOperOrPreStartMode");
5953  int Position;
5954  TTrackElement TrackElement;
5955  if(Track->FindNonPlatformMatch(18, HLoc, VLoc, Position, TrackElement));
5956  {
5957  if((TrackElement.TrackType == GapJump) && (TrackElement.Conn[0] > -1))
5958  {
5959  if((TrackElement.TrainIDOnElement == -1) && (Track->TrackElementAt(819, TrackElement.Conn[0]).TrainIDOnElement == -1))
5960  { // don't flash if train on either gap element
5961  Track->GapFlashGreenPosition = TrackElement.Conn[0];
5965  Track->GapFlashRedPosition = Position;
5969  Track->GapFlashFlag = true;
5970  }
5971  }
5972  }
5973  Utilities->CallLogPop(67);
5974  return; // covers above else & included here in case any more usermodes added later
5975  }
5976 
5977 // Left Mouse Button Functions
5978  if(RouteCancelFlag)
5980  mbLeftDown = true;
5981 
5982  if(Level2TrackMode == AddTrack)
5983  {
5984  TrainController->LogEvent("mbLeft + AddTrack");
5985  Screen->Cursor = TCursor(-11); // Hourglass;
5987  bool TrackLinkingRequiredFlag;
5988  int CurrentTag;
5989  TSpeedButton *TempSpeedButton = 0;
5990  if(CurrentSpeedButton)
5991  {
5992  CurrentTag = CurrentSpeedButton->Tag;
5993  TempSpeedButton = CurrentSpeedButton;
5994  }
5995  else
5996  CurrentTag = 0;
5997  bool InternalChecks = true;
5998  Track->PlotAndAddTrackElement(1, CurrentTag, 0, HLoc, VLoc, TrackLinkingRequiredFlag, InternalChecks);
5999  // above now has extra zero 'Aspect' parameter at v2.2.0 so can distinguish between adding track and pasting
6000  EditMenu->Enabled = true;
6001  if(Track->NamedLocationElementAt(1, HLoc, VLoc))
6002  ClearandRebuildRailway(7); // so named location graphics plotted correctly
6003  if(TrackLinkingRequiredFlag)
6004  {
6005  Track->SetTrackFinished(false);
6006  }
6007  SetTrackBuildImages(10);
6008  SetGapsButton->Enabled = false; // if conditions have changed need to reset buttons, best not calling SetLevel2TrackMode as that
6009  TrackOKButton->Enabled = false; // calls Clearand.. if gridflag set & takes a long time
6010  if(Track->GapsUnset(2))
6011  {
6012  SetGapsButton->Enabled = true;
6013  }
6014  // only enable if there are gaps still to be set (returns false for no track)
6015  else
6016  {
6017  if(!(Track->NoActiveTrack(1)) && !(Track->IsTrackFinished()))
6018  {
6019  TrackOKButton->Enabled = true;
6020  }
6021  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
6022  }
6023  if(!(Track->IsTrackFinished())) // can only set lengths for several elements together if TrackFinished
6024  {
6025  SetLengthsButton->Enabled = false;
6026  }
6027  if(TempSpeedButton) // restore button if was pressed
6028  {
6029  CurrentSpeedButton = TempSpeedButton;
6030  CurrentSpeedButton->Down = true;
6031  }
6032  Screen->Cursor = TCursor(-2); // Arrow
6033  Utilities->CallLogPop(44);
6034  return;
6035  }
6036 
6037  else if(Level2TrackMode == AddGraphic)
6038  {
6039  TrainController->LogEvent("mbLeft + AddGraphic");
6040  ResetChangedFileDataAndCaption(24, false);
6041  TUserGraphicItem NewGI;
6042  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
6043  if(UGMIt != Track->UserGraphicMap.end()) // if it is the end then nothing was found
6044  {
6045  NewGI.UserGraphic = UGMIt->second;
6046  NewGI.Width = UGMIt->second->Width;
6047  NewGI.Height = UGMIt->second->Height;
6049  NewGI.HPos = X + (Display->DisplayOffsetH * 16);
6050  NewGI.VPos = Y + (Display->DisplayOffsetV * 16);
6051  Track->UserGraphicVector.push_back(NewGI);
6052  Display->PlotAndAddUserGraphic(1, NewGI);
6053  }
6054  else
6055  {
6056  ShowMessage("Unable to find graphic file " + SelectedGraphicFileName + ". Check it still exists.");
6057  Utilities->CallLogPop(2195);
6058  return;
6059  }
6060  MoveTextOrGraphicButton->Enabled = true;
6061  EditMenu->Enabled = true;
6062  Utilities->CallLogPop(2182);
6063  return;
6064  }
6065 
6066  else if(Level2TrackMode == AddLocationName)
6067  {
6068  TrainController->LogEvent("mbLeft + AddLocationName");
6070  bool FoundFlag;
6071  TTrackElement TrackElement;
6072  AnsiString NameString;
6073  TTrack::TIMPair InactivePair = Track->GetVectorPositionsFromInactiveTrackMap(1, HLoc, VLoc, FoundFlag);
6074  if(!FoundFlag)
6075  {
6076  Utilities->CallLogPop(45);
6077  return; // inactive element not found (has to be a platform or named non-station location, can't select any other element)
6078  }
6079  TTrackElement& InactiveTrackElement1 = Track->InactiveTrackElementAt(28, InactivePair.first);
6080  TTrackElement& InactiveTrackElement2 = Track->InactiveTrackElementAt(29, InactivePair.second); // may be same element if only 1
6081  TTrackElement& ValidElement = InactiveTrackElement1;
6082  unsigned int ValidPosition;
6083  if((InactiveTrackElement1.TrackType != Platform) && (InactiveTrackElement2.TrackType != Platform) &&
6084  (InactiveTrackElement1.TrackType != NamedNonStationLocation) && (InactiveTrackElement2.TrackType != NamedNonStationLocation) &&
6085  (InactiveTrackElement1.TrackType != Concourse) && (InactiveTrackElement2.TrackType != Concourse))
6086  {
6087  Utilities->CallLogPop(46);
6088  return; // element not valid
6089  }
6090  if((InactiveTrackElement1.TrackType == Platform) || (InactiveTrackElement1.TrackType == NamedNonStationLocation) ||
6091  (InactiveTrackElement1.TrackType == Concourse))
6092  {
6093  ValidElement = InactiveTrackElement1;
6094  ValidPosition = InactivePair.first;
6095  }
6096  else if((InactiveTrackElement2.TrackType == Platform) || (InactiveTrackElement2.TrackType == NamedNonStationLocation) ||
6097  (InactiveTrackElement2.TrackType == Concourse))
6098  {
6099  ValidElement = InactiveTrackElement2;
6100  ValidPosition = InactivePair.second;
6101  }
6102  // now have required element as ValidElement & position in InactiveTrackvector as ValidPosition
6103 
6104  // put a square box round element to show selection
6105  Display->Rectangle(0, HLoc * 16, VLoc * 16, clB0G0R5, 0, 2);
6106  LocationNameTextBox->Visible = true;
6107  LocationNameTextBox->SetFocus();
6108  NameString = Track->GetLocationName(ValidPosition);
6109  LocationNameTextBox->Text = NameString;
6110  InfoPanel->Visible = true;
6111  InfoPanel->Caption = "NAMING LOCATIONS: Enter name, 'Carriage Return' to accept, 'Escape' to quit";
6112 
6113  Track->LNPendingList.clear();
6114  Track->LNPendingList.insert(Track->LNPendingList.end(), ValidPosition);
6115  Level2TrackMode = NoTrackMode; // if leave as AddLocationName can select other squares before enter name
6116  Utilities->CallLogPop(47);
6117  return;
6118  }
6119 
6120  else if(Level2TrackMode == DistanceStart) // new for extended distances - similar to !PrefDirContinuing
6121  // prior to selecting start element
6122  {
6123  TrainController->LogEvent("mbLeft + DistanceStart");
6125  if(ConstructPrefDir->GetPrefDirStartElement(0, HLoc, VLoc))
6126  {
6129  SetLevel1Mode(65);
6131  SetLevel2TrackMode(30);
6132  }
6133  Utilities->CallLogPop(48);
6134  return;
6135  }
6136 
6137  else if(Level2TrackMode == DistanceContinuing) // new for extended distances - similar to PrefDirContinuing
6138  // prior to selecting finish element
6139  {
6140  TrainController->LogEvent("mbLeft + DistanceContinuing");
6142  bool FinishElement = false, LeadingPointsAtLastElement = false;
6143  Screen->Cursor = TCursor(-11); // Hourglass;
6144  if((ConstructPrefDir->PrefDirSize() != 1) || (ConstructPrefDir->GetFixedPrefDirElementAt(181, 0).HLoc != HLoc) ||
6145  (ConstructPrefDir->GetFixedPrefDirElementAt(182, 0).VLoc != VLoc))
6146  { // not same as start element
6147  if(ConstructPrefDir->GetNextPrefDirElement(0, HLoc, VLoc, FinishElement))
6148  {
6151  ConstructPrefDir->CalcDistanceAndSpeed(1, OverallDistance, OverallSpeedLimit, LeadingPointsAtLastElement);
6152  if(FinishElement)
6153  {
6154  TrackLengthPanel->Visible = true;
6155  TrackLengthPanel->SetFocus();
6156  InfoPanel->Visible = true;
6157  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Set values (overall length), or right click to cancel/truncate";
6158  RestoreAllDefaultLengthsButton->Enabled = true;
6159  ResetDefaultLengthButton->Enabled = true;
6160  LengthOKButton->Enabled = true;
6161  DistanceBox->Text = AnsiString(OverallDistance);
6162  if(OverallSpeedLimit > -1)
6163  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6164  else
6165  SpeedLimitBox->Text = "Mixed";
6167  Screen->Cursor = TCursor(-2); // Arrow
6168  Utilities->CallLogPop(1527);
6169  return;
6170  }
6171  else
6172  {
6173  if(!LeadingPointsAtLastElement)
6174  {
6175  TrackLengthPanel->Visible = true;
6176  TrackLengthPanel->SetFocus();
6177  InfoPanel->Visible = true;
6178  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
6179  RestoreAllDefaultLengthsButton->Enabled = true;
6180  ResetDefaultLengthButton->Enabled = true;
6181  LengthOKButton->Enabled = true;
6182  DistanceBox->Text = AnsiString(OverallDistance);
6183  if(OverallSpeedLimit > -1)
6184  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6185  else
6186  SpeedLimitBox->Text = "Mixed";
6187  // Level2TrackMode = DistanceContinuing;
6188  // SetLevel2TrackMode();
6189  }
6190  else
6191  {
6192  TrackLengthPanel->Visible = true;
6193  TrackLengthPanel->SetFocus();
6194  InfoPanel->Visible = true;
6195  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Can't end on leading points, need to continue or truncate";
6196  RestoreAllDefaultLengthsButton->Enabled = false;
6197  ResetDefaultLengthButton->Enabled = false;
6198  LengthOKButton->Enabled = false;
6199  // Level2TrackMode = DistanceContinuing;
6200  // SetLevel2TrackMode();
6201  }
6202  }
6203  }
6204  }
6205  else // same as start element
6206  {
6209  SetLevel2TrackMode(54);
6210  Screen->Cursor = TCursor(-2); // Arrow
6211  Utilities->CallLogPop(1713);
6212  return;
6213  }
6215  Screen->Cursor = TCursor(-2); // Arrow
6216  Utilities->CallLogPop(1490);
6217  return;
6218  }
6219 
6220  else if(Level2TrackMode == GapSetting)
6221  {
6222  TrainController->LogEvent("mbLeft + GapSetting");
6224  // HighLightOneGap already called once from SetLevel2TrackMode so have all gap element values set
6225  // & it is highlighted
6226  if(!(Track->FindSetAndDisplayMatchingGap(1, HLoc, VLoc)))
6227  {
6228  Utilities->CallLogPop(50);
6229  return; // true if finds one
6230  }
6231  InfoPanel->Visible = true;
6232  InfoPanel->Caption = "CONNECTING GAPS: Connecting element selected";
6233  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
6234  Delay(0, 500); // 500 msec delay before next selection requested
6235 
6236  // ClearandRebuildRailway(8);//get rid of gap selections
6237  // need to call this later when new gap displayed, else old gap remains
6238 
6239  // now back to highlighting next gap
6240  // bool LocError = false;
6241  if(!(HighLightOneGap(1, HLoc, VLoc)))
6242  {
6243  // all gaps set
6244  ShowMessage("All gaps set");
6245  if(Level2TrackMode == AddTrack)
6246  {
6248  SetLevel1Mode(66);
6249  SetLevel2TrackMode(31);
6250  }
6251  else
6252  {
6254  SetLevel1Mode(37);
6255  }
6256  ClearandRebuildRailway(9); // get rid of last gap ellipse
6257  Utilities->CallLogPop(51);
6258  return;
6259  }
6260  // here if one gap highlighted so return to user to allow corresponding gap to be selected
6261  // by another call to MainScreenMouseDown
6262  }
6263 
6264  else if(Level2TrackMode == AddText)
6265  {
6266  TrainController->LogEvent("mbLeft + AddText");
6268  // X & Y are relative to Display output, but TextBox is placed relative to Form
6269  // if mouse position on first character of an existing piece of text reload it into the editor
6270 
6271  bool TextFoundFlag = false;
6272  int TrueX = 0, TrueY = 0;
6273  AnsiString ExistingText = "";
6275  TFont *ExistingTextFont = new TFont;
6276  int ExistingTextHPos = 0, ExistingTextVPos = 0;
6277  Track->GetTruePositionsFromScreenPos(1, TrueX, TrueY, X, Y);
6278  if(!TextHandler->TextVector.empty())
6279  {
6280  for(TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin(); TextPtr--)
6281  {
6282  if((TrueX >= (*TextPtr).HPos) && (TrueX < ((*TextPtr).HPos + abs((*TextPtr).Font->Height))) && (TrueY >= (*TextPtr).VPos) && (TrueY <
6283  ((*TextPtr).VPos + abs((*TextPtr).Font->Height))))
6284  {
6285  ExistingText = (*TextPtr).TextString;
6286  ExistingTextFont->Assign((*TextPtr).Font);
6287  ExistingTextHPos = (*TextPtr).HPos;
6288  ExistingTextVPos = (*TextPtr).VPos;
6289  TextFoundFlag = true;
6290  TextHandler->TextErase(9, TrueX, TrueY);
6291  break;
6292  } // if ....
6293  } // for TextPtr...
6294  } // if !TextVector...
6295 
6296  if(TextFoundFlag)
6297  {
6298  TextBox->Left = ExistingTextHPos + Display->Left() - (Display->DisplayOffsetH * 16) - 3;
6299  TextBox->Top = ExistingTextVPos + Display->Top() - (Display->DisplayOffsetV * 16) - 3;
6300  TextBox->Font->Assign(ExistingTextFont);
6301  Display->SetFont(ExistingTextFont);
6302  Text_X = ExistingTextHPos;
6303  Text_Y = ExistingTextVPos;
6304  }
6305  else
6306  {
6307  TextBox->Left = (TextOrUserGraphicGridVal * div((Display->Left() + X), TextOrUserGraphicGridVal).quot) - 3;
6308  TextBox->Top = (TextOrUserGraphicGridVal * div((Display->Top() + Y), TextOrUserGraphicGridVal).quot) - 3;
6309  TextBox->Font->Assign(Display->GetFont());
6310  Text_X = TextOrUserGraphicGridVal * div(NoOffsetX, TextOrUserGraphicGridVal).quot;
6311  Text_Y = TextOrUserGraphicGridVal * div(NoOffsetY, TextOrUserGraphicGridVal).quot;
6312  }
6313  TextBox->Visible = true;
6314  TextBox->SetFocus();
6315  if(TextFoundFlag)
6316  TextBox->Text = ExistingText;
6317  else
6318  TextBox->Text = "New Text: CR=end, ESC=quit";
6319  TextBox->Width = (abs(TextBox->Font->Height) * TextBox->Text.Length() * 0.7);
6320  TextBox->SelectAll();
6321  delete ExistingTextFont;
6322  ClearandRebuildRailway(29); // to remove old text if replaced
6324  Utilities->CallLogPop(1775);
6325  return; // If text input go no further
6326  }
6327 
6329  {
6330  TrainController->LogEvent("mbLeft + MoveTextOrGraphic");
6332  // int HPosInput;// = X + (Display->DisplayOffsetH * 16);
6333  // int VPosInput;// = Y + (Display->DisplayOffsetV * 16);
6334  // Track->GetTruePositionsFromScreenPos(HPosInput, VPosInput, X, Y);
6335  // StartX = X + (Display->DisplayOffsetH * 16);
6336  // StartY = Y + (Display->DisplayOffsetV * 16);
6339  if(!TextFoundFlag) // give precedence to text
6340  {
6342  }
6343  Utilities->CallLogPop(53);
6344  return; // if text move selected don't permit anything else
6345  }
6346 
6347  else if(Level2TrackMode == TrackSelecting)
6348 /* When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
6349  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
6350  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
6351  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
6352  selected rectangle.
6353 */
6354  {
6355  TrainController->LogEvent("mbLeft + TrackSelecting");
6356  ClearandRebuildRailway(10); // to get rid of earlier rectangles
6357  SelectStartPair.first = HLoc;
6358  SelectStartPair.second = VLoc;
6359  }
6360 
6361  else if((Level2TrackMode == CopyMoving) || (Level2TrackMode == CutMoving))
6362 /* The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
6363  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
6364  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
6365  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
6366 */
6367  {
6368  TrainController->LogEvent("mbLeft + CopyMoving or CutMoving");
6370  if((X < ((SelectBitmapHLoc - Display->DisplayOffsetH) * 16) + 4) ||
6371  (X > ((SelectBitmapHLoc + (SelectBitmap->Width / 16) - Display->DisplayOffsetH) * 16) - 4))
6372  {
6373  SelectPickedUp = false;
6374  Utilities->CallLogPop(54);
6375  return; // within 4 pixels of outside of horizontal area (4 pixels are so can't push selection off edge of screen)
6376  }
6377  if((Y < ((SelectBitmapVLoc - Display->DisplayOffsetV) * 16) + 4) ||
6378  (Y > ((SelectBitmapVLoc + (SelectBitmap->Height / 16) - Display->DisplayOffsetV) * 16) - 4))
6379  {
6380  SelectPickedUp = false;
6381  Utilities->CallLogPop(55);
6382  return; // within 4 pixels of outside of vertical area (4 pixels are so can't push selection off edge of screen)
6383  }
6384  else
6385  {
6386  SelectPickedUp = true;
6387  }
6390  }
6391 
6393  {
6394  TrainController->LogEvent("mbLeft + != PrefDirContinuing");
6395  ResetChangedFileDataAndCaption(15, false);
6396 // RlyFile = false; - don't alter this just for PrefDir changes
6397  if(ConstructPrefDir->GetPrefDirStartElement(1, HLoc, VLoc))
6398  {
6402  }
6403  Utilities->CallLogPop(56);
6404  return;
6405  }
6406 
6408  {
6409  TrainController->LogEvent("mbLeft + PrefDirContinuing");
6410  ResetChangedFileDataAndCaption(16, false);
6411 // RlyFile = false; - don't alter this just for PrefDir changes
6412  bool FinishElement;
6413  Screen->Cursor = TCursor(-11); // Hourglass;
6414  if((ConstructPrefDir->PrefDirSize() != 1) || (ConstructPrefDir->GetFixedPrefDirElementAt(183, 0).HLoc != HLoc) ||
6415  (ConstructPrefDir->GetFixedPrefDirElementAt(184, 0).VLoc != VLoc))
6416  { // not same as start element
6417  if(ConstructPrefDir->GetNextPrefDirElement(1, HLoc, VLoc, FinishElement))
6418  {
6420  if(FinishElement)
6421  {
6422  ShowMessage("Preferred direction added");
6425  SetLevel1Mode(16);
6426  Screen->Cursor = TCursor(-2); // Arrow
6427  Utilities->CallLogPop(57);
6428  return;
6429  }
6430  else
6431  {
6434  }
6435  // set again since 1st time
6436  // PrefDir vector only had start element & Truncate wasn't enabled, also need
6437  // to do the checks for Loop & End for each element as it is added
6438  }
6439  }
6440  else // same as start element
6441  {
6444  SetLevel1Mode(121);
6445  Screen->Cursor = TCursor(-2); // Arrow
6446  Utilities->CallLogPop(1714);
6447  return;
6448  }
6449  Screen->Cursor = TCursor(-2); // Arrow
6450  Utilities->CallLogPop(58);
6451  return;
6452  }
6453 
6455  {
6456  TrainController->LogEvent("mbLeft + PrefDirSelecting");
6457  ClearandRebuildRailway(56); // to get rid of earlier rectangles
6458  SelectStartPair.first = HLoc;
6459  SelectStartPair.second = VLoc;
6460  }
6461 
6462  else if(Level1Mode == OperMode)
6463  {
6464  if((Level2OperMode == Operating) && CallingOnButton->Down && CallingOnButton->Enabled)
6465  {
6466  TrainController->LogEvent("mbLeft + Operating & CallingOnButton->Down");
6467  int Position;
6468  TTrackElement TrackElement;
6469  if(Track->FindNonPlatformMatch(2, HLoc, VLoc, Position, TrackElement))
6470  {
6471  if(TrackElement.TrackType != SignalPost)
6472  {
6473  CallingOnButton->Down = false;
6474 // InfoPanel->Visible = false; //dropped at v1.3.0, not sure what purpose intended to serve but don't want to lose the info panel as did with this here also added line below to reset
6476  Utilities->CallLogPop(59);
6477  return;
6478  }
6479  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
6480  {
6482  {
6484  x).LeadExitPos] == Position) && (TrackElement.Config[Track->TrackElementAt(429, TrainController->TrainVectorAt(28,
6486  {
6487  // found it!
6488 /*
6489  if(TrackElement.SpeedTag == 68)
6490  {
6491  Display->PlotOutput(0, (HLoc * 16), (VLoc * 16), RailGraphics->bm68CallingOn);
6492  }
6493  if(TrackElement.SpeedTag == 69)
6494  {
6495  Display->PlotOutput(1, (HLoc * 16), (VLoc * 16), RailGraphics->bm69CallingOn);
6496  }
6497  if(TrackElement.SpeedTag == 70)
6498  {
6499  Display->PlotOutput(2, (HLoc * 16), (VLoc * 16), RailGraphics->bm70CallingOn);
6500  }
6501  if(TrackElement.SpeedTag == 71)
6502  {
6503  Display->PlotOutput(3, (HLoc * 16), (VLoc * 16), RailGraphics->bm71CallingOn);
6504  }
6505  if(TrackElement.SpeedTag == 72)
6506  {
6507  Display->PlotOutput(4, (HLoc * 16), (VLoc * 16), RailGraphics->bm72CallingOn);
6508  }
6509  if(TrackElement.SpeedTag == 73)
6510  {
6511  Display->PlotOutput(5, (HLoc * 16), (VLoc * 16), RailGraphics->bm73CallingOn);
6512  }
6513  if(TrackElement.SpeedTag == 74)
6514  {
6515  Display->PlotOutput(6, (HLoc * 16), (VLoc * 16), RailGraphics->bm74CallingOn);
6516  }
6517  if(TrackElement.SpeedTag == 75)
6518  {
6519  Display->PlotOutput(7, (HLoc * 16), (VLoc * 16), RailGraphics->bm75CallingOn);
6520  }
6521 */
6522  Track->TrackElementAt(430, Position).CallingOnSet = true;
6523  Track->PlotSignal(13, Track->TrackElementAt(893, Position), Display);
6524 // added at v 1.3.0 in place of the above to ensure ground signals (as well as others) plot correctly for proceed
6525  // have to call after CallingOnSet becomes true & can't use TrackElement as that still has CallingOnSet false
6526  ClearandRebuildRailway(69); // added at v1.3.0 to replot route on element after PlotSignal above
6529  CallingOnButton->Down = false;
6531 
6532 // set an unrestricted route into the station (just to the first platform) from the stop signal (note that it may be last in an autosigs
6533 // route) but remove any single route elements first (can't reach here if constructing a route), else may try to extend a route that
6534 // has been removed (only a precaution, shouldn't cause any probs whether single route set or not)
6535  for(unsigned int x = 0; x < AllRoutes->AllRoutesSize(); x++)
6536  {
6537  if(AllRoutes->GetFixedRouteAt(192, x).PrefDirSize() == 1)
6538  {
6539  // only allow route element to be removed if not selected for a route start otherwise
6540  // StartSelectionRouteID will be set & will fail at convert
6542  {
6544  AllRoutes->RemoveRouteElement(21, PDE.HLoc, PDE.VLoc, PDE.GetELink());
6545  TrainController->LogEvent("SingleRouteElementRemovedDuringCallon, H = " + AnsiString(PDE.HLoc) + ", V = " +
6546  AnsiString(PDE.VLoc));
6547  }
6548  }
6549  }
6550 
6551 // find the correct entry in CallonVector - i.e. where Position == RouteStartEntry
6552  for(unsigned int x = 0; x < AllRoutes->CallonVector.size(); x++)
6553  {
6554  if(AllRoutes->CallonVector.at(x).RouteStartPosition == Position)
6555  { // found it
6556  if(!(AllRoutes->CallonVector.at(x).RouteOrPartRouteSet))
6557  // if RouteOrPartRouteSet false then set an unrestricted route into platform
6558  {
6559  bool PointsChanged = false;
6560  IDInt ReqPosRouteID(-1);
6561  TOneRoute *NewRoute = new TOneRoute;
6562  bool CallonTrue = true;
6563  bool ConsecSignalsRouteFalse = false;
6564  if(NewRoute->GetNonPreferredRouteStartElement(1,
6565  Track->TrackElementAt(841, AllRoutes->CallonVector.at(x).RouteStartPosition).HLoc,
6566  Track->TrackElementAt(842, AllRoutes->CallonVector.at(x).RouteStartPosition).VLoc, ConsecSignalsRouteFalse,
6567  CallonTrue))
6568  {
6569  if(NewRoute->GetNextNonPreferredRouteElement(1,
6570  Track->TrackElementAt(843, AllRoutes->CallonVector.at(x).PlatformPosition).HLoc,
6571  Track->TrackElementAt(844, AllRoutes->CallonVector.at(x).PlatformPosition).VLoc, ConsecSignalsRouteFalse,
6572  CallonTrue, ReqPosRouteID, PointsChanged))
6573  {
6574  if(!PointsChanged) // shouldn't be changed, something wrong if true so don't plot route
6575  {
6576  NewRoute->ConvertAndAddNonPreferredRouteSearchVector(3, ReqPosRouteID);
6577  ClearandRebuildRailway(67); // to plot the route (only finds one so won't call repeatedly)
6578  }
6579  }
6580  }
6581  delete NewRoute;
6582  }
6583  }
6584  }
6585 // InfoPanel->Visible = false;
6586  Utilities->CallLogPop(60);
6587  return;
6588  }
6589  }
6590  }
6591  }
6592  CallingOnButton->Down = false;
6594  Utilities->CallLogPop(61);
6595  return;
6596  }
6597 /* get 1st element, first check if selected points, not in existing route, & in RouteNotStarted mode
6598  if so, set all the flash values, Track->PointFlashFlag & start time, then exit for flasher to take over.
6599  If any of above conditions not met then treat as route selection, setting route flasher if
6600  route continuing.
6601 */
6602 
6603  if((Level2OperMode == Operating) || (Level2OperMode == PreStart)) // not 'else if' as both may apply
6604  // disallow route setting if paused
6605  {
6606  if(Level2OperMode == PreStart)
6607  {
6608  PointsFlashDuration = 0.0;
6611  }
6612  else
6613  {
6614  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
6615  if(TTClockSpeed < 1)
6616  TempSpeedVal = TTClockSpeed;
6617  PointsFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
6620  }
6621  if(RouteMode == RouteNotStarted)
6622  {
6623  TrainController->LogEvent("mbLeft + RouteNotStarted");
6624  int Position;
6625  TTrackElement TrackElement;
6626  if(Track->FindNonPlatformMatch(3, HLoc, VLoc, Position, TrackElement))
6627  {
6628  if((TrackElement.TrackType == Points) && !(AllRoutes->TrackIsInARoute(1, Position, 0))
6630  // Flash selected points & changeover if appropriate
6631  // need !Track->PointFlashFlag to prevent another point being selected while another is flashing, & !Track->RouteFlashFlag
6632  // to ensure user only does one thing at a time
6633  {
6634  if(TrackElement.TrainIDOnElement > -1)
6635  {
6636  TrainController->StopTTClockMessage(1, "Can't change points under a train!");
6637  Utilities->CallLogPop(62);
6638  return;
6639  }
6640  PointFlash->SetScreenHVSource(1, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
6641 
6642 /*
6643  This used to try to allow any linked trailing edges to cause both points to change, but no good if
6644  there are two adjacent crossovers, where both trailing edges are linked to two different points.
6645  The wrong link might be chosen. Also doubtful if applying a strict order of checks would work, since
6646  may be obscure configurations that would be wrong. This function bypasses the MatchingPoint check, which
6647  ensures that there are no obscure links. Hence better to stick with original.
6648 
6649  //check if trailing edge linked to another point trailing edge
6650  int DivergingPosition = TrackElement.Conn[1];
6651  TTrackElement DivergingElement = Track->TrackElementAt(431, TrackElement.Conn[1]);
6652  DivergingPointVectorPosition = -1;
6653  if((DivergingElement.TrackType == Points) &&
6654  ((DivergingElement.Conn[1] == Position) || (DivergingElement.Conn[3] == Position)))
6655  {
6656  if(AllRoutes->TrackIsInARoute(, DivergingPosition))
6657  {
6658  ShowMessage("Linked points Locked");
6659  }
6660  else DivergingPointVectorPosition = DivergingPosition;
6661  }
6662  else
6663  {
6664  DivergingPosition = TrackElement.Conn[3];
6665  DivergingElement = Track->TrackElementAt(432, TrackElement.Conn[3]);
6666  if((DivergingElement.TrackType == Points) &&
6667  ((DivergingElement.Conn[1] == Position) || (DivergingElement.Conn[3] == Position)))
6668  {
6669  if(AllRoutes->TrackIsInARoute(, DivergingPosition))
6670  {
6671  ShowMessage("Linked points locked");
6672  }
6673  else DivergingPointVectorPosition = DivergingPosition;
6674  }
6675  }
6676  Track->PointFlashFlag = true;
6677  PointFlashVectorPosition = Position;
6678  PointFlashStartTime = TrainController->TTClockTime;
6679  [close curly bracket - if include it matches earlier non-commented one!]
6680 */
6681  TTrackElement DivergingElement = Track->TrackElementAt(433, TrackElement.Conn[3]);
6682  int DivergingPosition = TrackElement.Conn[3];
6683  if((DivergingElement.TrackType == Points) && (DivergingElement.Conn[3] == Position) && (Track->MatchingPoint(1, Position,
6684  DivergingPosition))) // full match inc same attributes
6685  {
6686  if(AllRoutes->TrackIsInARoute(4, DivergingPosition, 0))
6687  {
6688  TrainController->StopTTClockMessage(2, "Linked points locked");
6689  }
6690  else
6691  {
6692  Track->PointFlashFlag = true;
6693  PointFlashVectorPosition = Position;
6694  DivergingPointVectorPosition = DivergingPosition;
6696  }
6697  }
6698  else // no matching point, just change this point
6699  {
6700  Track->PointFlashFlag = true;
6701  PointFlashVectorPosition = Position;
6704  }
6705  }
6706 /* drop manual changing of level crossings - only allow changing by setting a route through them
6707  else if((Track->IsLCAtHV(23, HLoc, VLoc) && !Track->PointFlashFlag && !Track->RouteFlashFlag))//level crossing
6708  {
6709  TTrack::TFlashLevelCrossing FLC;
6710  FLC.LCHLoc = HLoc;
6711  FLC.LCVLoc = VLoc;
6712  FLC.LCChangeStartTime = TrainController->TTClockTime;
6713  FLC.LCBaseElementSpeedTag = TrackElement.SpeedTag;
6714  if(Track->IsLCBarrierDownAtHV(0, HLoc, VLoc))
6715  {
6716  FLC.LCChangeDuration = LevelCrossingBarrierUpFlashDuration;
6717  FLC.BarrierState = TTrack::Raising;
6718  }
6719  else
6720  {
6721  FLC.LCChangeDuration = LevelCrossingBarrierDownFlashDuration;
6722  FLC.BarrierState = TTrack::Lowering;
6723  }
6724  Track->SetLinkedLevelCrossingBarrierAttributes(, HLoc, VLoc, 2);//set attr to 2 for changing state
6725  Track->ChangingLCVector.push_back(FLC);
6726  }
6727 */ else // route start
6728  {
6729  if(AutoSigsFlag)
6730  {
6731  AutoRouteStartMarker->SetScreenHVSource(2, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
6733  }
6734  else if(ConsecSignalsRoute)
6735  {
6736  SigRouteStartMarker->SetScreenHVSource(3, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
6738  }
6739  else
6740  {
6741  NonSigRouteStartMarker->SetScreenHVSource(4, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
6743  }
6744  if(PreferredRoute)
6745  {
6746  if(!Track->PointFlashFlag && !Track->RouteFlashFlag) // don't allow a route to start if a point changing or
6747  // another route building
6748  {
6749  ConstructRoute->ClearRoute(); // in case not empty though should be
6751  {
6752  if(AutoSigsFlag)
6754  else
6757  InfoPanel->Visible = true;
6758  if(Level2OperMode == PreStart)
6759  InfoPanel->Caption = "PRE-START: Select next route location";
6760  else
6761  InfoPanel->Caption = "OPERATING: Select next route location";
6762  }
6763  }
6764  Utilities->CallLogPop(63);
6765  return;
6766  }
6767  else // nonpreferred route
6768  {
6769  if(!Track->PointFlashFlag && !Track->RouteFlashFlag) // don't allow a route to start if a point changing or
6770  // another route building
6771  {
6772  ConstructRoute->ClearRoute(); // in case not empty though should be
6773  bool CallonFalse = false;
6774  if(ConstructRoute->GetNonPreferredRouteStartElement(0, HLoc, VLoc, ConsecSignalsRoute, CallonFalse))
6775  {
6778  InfoPanel->Visible = true;
6779  if(Level2OperMode == PreStart)
6780  InfoPanel->Caption = "PRE-START: Select next route location";
6781  else
6782  InfoPanel->Caption = "OPERATING: Select next route location";
6783  }
6784  }
6785  Utilities->CallLogPop(64);
6786  return;
6787  } // NonPreferred route
6788  } // TrackType != Points
6789  } // if(Track->FindNonPlatformMatch(HLoc, VLoc, Position, TrackElement))
6790  } // if(RouteMode == RouteNotStarted)
6791  else // RouteContinuing
6792  {
6793  TrainController->LogEvent("mbLeft + RouteContinuing");
6794  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
6797  AutoRouteStartMarker->PlotOriginal(14, Display); // if overlay not plotted will ignore
6798  SigRouteStartMarker->PlotOriginal(15, Display); // if overlay not plotted will ignore
6799  NonSigRouteStartMarker->PlotOriginal(16, Display); // if overlay not plotted will ignore
6800  Screen->Cursor = TCursor(-11); // Hourglass - also set to an hourglass when flashing, after found required
6801  // element, but this sets it to an hourglass while searching
6802  bool PointsChanged = false;
6803  if(PreferredRoute)
6804  {
6805  // route added to AllRoutes in GetNextRouteElement if valid
6806  // int ReqPosRouteNumber;
6808  ConstructRoute->ReqPosRouteID, PointsChanged))
6809  {
6810  Track->RouteFlashFlag = true;
6811  PreferredRouteFlag = true;
6812  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
6813  if(TTClockSpeed < 1)
6814  TempSpeedVal = TTClockSpeed;
6815  if(Level2OperMode == PreStart)
6816  RouteFlashDuration = 0.0;
6817  else if(PointsChanged)
6818  RouteFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
6819  else
6820  RouteFlashDuration = AllRoutes->SignalsDelay * TempSpeedVal;
6821  ConstructRoute->SetRouteFlashValues(1, AutoSigsFlag, true); // true for ConsecSignalsRoute
6823  }
6824  else
6825  {
6827  }
6828  Screen->Cursor = TCursor(-2); // Arrow
6829  TrainController->BaseTime = TDateTime::CurrentDateTime();
6831  Utilities->CallLogPop(65);
6832  return;
6833  }
6834  else
6835  {
6836  bool CallonFalse = false;
6838  PointsChanged))
6839  {
6840  Track->RouteFlashFlag = true;
6841  PreferredRouteFlag = false;
6842  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
6843  if(TTClockSpeed < 1)
6844  TempSpeedVal = TTClockSpeed;
6845  if(Level2OperMode == PreStart)
6846  RouteFlashDuration = 0.0;
6847  else if(PointsChanged)
6848  RouteFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
6849  else
6850  RouteFlashDuration = AllRoutes->SignalsDelay * TempSpeedVal;
6851  ConstructRoute->SetRouteFlashValues(2, false, false);
6853  }
6854  else
6855  {
6857  }
6858  }
6859  TrainController->BaseTime = TDateTime::CurrentDateTime();
6861  Screen->Cursor = TCursor(-2); // Arrow
6862  }
6863  Utilities->CallLogPop(66);
6864  return;
6865  }
6866  }
6867 
6868  Utilities->CallLogPop(68);
6869  }
6870  catch(const Exception &e)
6871  {
6872  ErrorLog(20, e.Message);
6873  }
6874 }
6875 
6876 // ---------------------------------------------------------------------------
6877 
6878 void TInterface::MainScreenMouseDown3(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
6879  // ZoomOut mode
6880 {
6881 // NB: DisplayZoomOutOffsetH & V take account of the Min & Max H & V values so don't need these again
6882  try
6883  {
6884  TrainController->LogEvent("MainScreenMouseDown3," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
6885  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MainScreenMouseDown3," + AnsiString(Button) + "," + AnsiString(X) +
6886  "," + AnsiString(Y));
6887  if(Button != mbLeft)
6888  {
6889  // this routine new at v2.1.0. Allows railway moving for zoom-out mode
6892  WholeRailwayMoving = true;
6893  Screen->Cursor = TCursor(-22); // Four arrows;
6894  }
6895  else
6896  {
6897  InfoPanel->Visible = false; // reset infopanel in case not set later
6898  InfoPanel->Caption = "";
6899  int HRounding, VRounding;
6900  int TruePosH = (X / 4) + Display->DisplayZoomOutOffsetH;
6901  int TruePosV = (Y / 4) + Display->DisplayZoomOutOffsetV;
6902  // find nearest screen centre - from 30 to 210 horiz & from 18 to 126 vert
6903  if(TruePosH < 0)
6904  HRounding = -(Utilities->ScreenElementWidth / 4);
6905  else
6906  HRounding = (Utilities->ScreenElementWidth / 4);
6907  int CentreH = (((TruePosH + HRounding) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2));
6908  while((CentreH - Track->GetHLocMax()) >= (Utilities->ScreenElementWidth / 2))
6909  CentreH -= (Utilities->ScreenElementWidth / 2);
6910  while((Track->GetHLocMin() - CentreH) >= (Utilities->ScreenElementWidth / 2))
6911  CentreH += (Utilities->ScreenElementWidth / 2);
6912  if(TruePosV < 0)
6913  VRounding = -(Utilities->ScreenElementHeight / 4);
6914  else
6915  VRounding = (Utilities->ScreenElementHeight / 4);
6916  int CentreV = (((TruePosV + VRounding) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2));
6917  while((CentreV - Track->GetVLocMax()) >= (Utilities->ScreenElementHeight / 2))
6918  CentreV -= (Utilities->ScreenElementHeight / 2);
6919  while((Track->GetVLocMin() - CentreV) >= (Utilities->ScreenElementHeight / 2))
6920  CentreV += (Utilities->ScreenElementHeight / 2);
6921  Display->DisplayOffsetH = CentreH - (Utilities->ScreenElementWidth / 2);
6923 
6924  TLevel2OperMode TempLevel2OperMode = Level2OperMode;
6925  if(Level1Mode == BaseMode)
6926  SetLevel1Mode(17);
6927  else if(Level1Mode == TrackMode)
6928  {
6929  // set edit menu items
6931  PreventGapOffsetResetting = true; // when return from zoom by clicking screen don't force a return to the
6932  // displayed gap, user wants to display the clicked area
6933  SetLevel2TrackMode(32); // revert to earlier track mode from zoom
6934  PreventGapOffsetResetting = false;
6935  }
6936  else if(Level1Mode == PrefDirMode)
6937  {
6939  SetLevel2PrefDirMode(3); // revert to earlier PrefDir mode from zoom
6940  else
6941  SetLevel1Mode(33); // if PrefDirSelecting revert to normap PrefDirMode
6942  }
6943  // else if(Level1Mode == TrackMode) SetLevel1Mode();//just revert to basic track mode from zoom
6944  // else if(Level1Mode == PrefDirMode) SetLevel1Mode();//just revert to basic PrefDir mode from zoom
6945  else if(Level1Mode == TimetableMode)
6946  {
6947  InfoPanel->Visible = false;
6948  }
6949  // Not OperMode or RestartSessionOperMode as that resets the performance file
6950  else if(TempLevel2OperMode == Operating) // similar to SetLevel2OperMode but without resetting BaseTime
6951  {
6952  OperateButton->Enabled = true;
6953  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
6954  ExitOperationButton->Enabled = true;
6956  }
6957  else if(TempLevel2OperMode == Paused) // similar to SetLevel2OperMode but without resetting RestartTime
6958  {
6959  OperateButton->Enabled = true;
6960  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
6961  ExitOperationButton->Enabled = true;
6962  TTClockAdjButton->Enabled = true;
6965  }
6966  else if(TempLevel2OperMode == PreStart)
6967  {
6968  OperateButton->Enabled = true;
6969  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
6970  ExitOperationButton->Enabled = true;
6971  TTClockAdjButton->Enabled = true;
6973  }
6974  Display->ZoomOutFlag = false; // reset this after level modes called so gap flash stays set if set to begin with
6977  }
6978  Utilities->CallLogPop(69);
6979  }
6980  catch(const Exception &e)
6981  {
6982  ErrorLog(21, e.Message);
6983  }
6984 }
6985 
6986 // ---------------------------------------------------------------------------
6987 
6988 void __fastcall TInterface::MainScreenMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
6989 {
6990  try
6991  {
6992  // TrainController->LogEvent("MainScreenMouseMove," + AnsiString(X) + "," + AnsiString(Y)); //dropped at v0.6, too many events
6993  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseMove," + AnsiString(X) + "," + AnsiString(Y));
6994 
6995  if(!mbLeftDown && WholeRailwayMoving) // new at v2.1.0
6996  {
6997  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
6999  if(X < 0)
7000  X = 0; // ensure pointer stays within display area
7001  if(X > (MainScreen->Width - 1))
7002  X = MainScreen->Width - 1;
7003  if(Y < 0)
7004  Y = 0;
7005  if(Y > (MainScreen->Height - 1))
7006  Y = MainScreen->Height - 1;
7007 
7008  if(!Display->ZoomOutFlag)
7009  {
7010  int StartOffsetX = (X - StartWholeRailwayMoveHPos) % 16;
7011  int StartOffsetY = (Y - StartWholeRailwayMoveVPos) % 16;
7012  if((abs(X - StartWholeRailwayMoveHPos) >= 16) || (abs(Y - StartWholeRailwayMoveVPos) >= 16))
7013  {
7014  int NewH = X - StartWholeRailwayMoveHPos;
7015  int NewV = Y - StartWholeRailwayMoveVPos;
7016  Display->DisplayOffsetH -= NewH / 16;
7017  Display->DisplayOffsetV -= NewV / 16;
7018  StartWholeRailwayMoveHPos = X - StartOffsetX;
7019  StartWholeRailwayMoveVPos = Y - StartOffsetY;
7022  {
7024  }
7025  }
7026  }
7027 
7028  else
7029  {
7030  int StartZOffsetX = (X - StartWholeRailwayMoveHPos) % 4;
7031  int StartZOffsetY = (Y - StartWholeRailwayMoveVPos) % 4;
7032  if((abs(X - StartWholeRailwayMoveHPos) >= 4) || (abs(Y - StartWholeRailwayMoveVPos) >= 4))
7033  {
7034  int NewH = X - StartWholeRailwayMoveHPos;
7035  int NewV = Y - StartWholeRailwayMoveVPos;
7036  Display->DisplayZoomOutOffsetH -= NewH / 4;
7037  Display->DisplayZoomOutOffsetV -= NewV / 4;
7038  StartWholeRailwayMoveHPos = X - StartZOffsetX;
7039  StartWholeRailwayMoveVPos = Y - StartZOffsetY;
7040  Display->ClearDisplay(10);
7042  }
7043  }
7044  TrainController->BaseTime = TDateTime::CurrentDateTime();
7046  }
7047 
7048  else if(mbLeftDown)
7049  {
7051 /* [Repeated from MouseDown] - When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
7052  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
7053  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
7054  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
7055  selected rectangle.
7056  [New] At this point the select starting position has been defined in SelectStartPair, and the current mouse position is defined (wrt whole
7057  railway) in HLoc & VLoc from the screen positions X & Y by GetTrackLocsFromScreenPos. Both are incremented so that the rectangle
7058  includes the current point (if no mouse movement at all occurs then a 1 x 1 rectangle is displayed). Limits are set to prevent the
7059  displayed rectangle extending off screen. Edges are set at 60 & 36 rather than 59 & 35 because the defined rectangle excludes the
7060  rightmost and bottom HLoc & VLoc values, if 59 & 35 were used the right & bottom screen edges wouldn't be reached. A TRect is then
7061  defined from SelectStartPair and the HLoc/VLoc values, Clearand... called to clear earlier rectangles, and a dashed edge drawn round
7062  the selection.
7063 */
7064  {
7065  TrainController->LogEvent("MouseMove + TrackSelecting");
7066  int CurrentHLoc, CurrentVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7067  Track->GetTrackLocsFromScreenPos(2, CurrentHLoc, CurrentVLoc, X, Y);
7068  // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7069  // rightmost point and the VLoc value of the bottommost point
7070  if(CurrentHLoc >= StartHLoc)
7071  CurrentHLoc++;
7072  else
7073  StartHLoc++;
7074  if(CurrentVLoc >= StartVLoc)
7075  CurrentVLoc++;
7076  else
7077  StartVLoc++;
7078  if(CurrentHLoc - Display->DisplayOffsetH > Utilities->ScreenElementWidth)
7080  if(CurrentVLoc - Display->DisplayOffsetV > Utilities->ScreenElementHeight)
7082  if(CurrentHLoc - Display->DisplayOffsetH < 0)
7083  CurrentHLoc = Display->DisplayOffsetH;
7084  if(CurrentVLoc - Display->DisplayOffsetV < 0)
7085  CurrentVLoc = Display->DisplayOffsetV;
7086  TRect TempRect(StartHLoc, StartVLoc, CurrentHLoc, CurrentVLoc);
7087  ClearandRebuildRailway(14); // to clear earlier rectangles
7088  Display->PlotDashedRect(0, TempRect);
7089  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
7090  }
7091 
7093  {
7094  TrainController->LogEvent("MouseMove + PrefDirSelecting");
7095 
7096  int CurrentHLoc, CurrentVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7097  Track->GetTrackLocsFromScreenPos(5, CurrentHLoc, CurrentVLoc, X, Y);
7098  // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7099  // rightmost point and the VLoc value of the bottommost point
7100  if(CurrentHLoc >= StartHLoc)
7101  CurrentHLoc++;
7102  else
7103  StartHLoc++;
7104  if(CurrentVLoc >= StartVLoc)
7105  CurrentVLoc++;
7106  else
7107  StartVLoc++;
7108  if(CurrentHLoc - Display->DisplayOffsetH > Utilities->ScreenElementWidth)
7110  if(CurrentVLoc - Display->DisplayOffsetV > Utilities->ScreenElementHeight)
7112  if(CurrentHLoc - Display->DisplayOffsetH < 0)
7113  CurrentHLoc = Display->DisplayOffsetH;
7114  if(CurrentVLoc - Display->DisplayOffsetV < 0)
7115  CurrentVLoc = Display->DisplayOffsetV;
7116  TRect TempRect(StartHLoc, StartVLoc, CurrentHLoc, CurrentVLoc);
7117  ClearandRebuildRailway(57); // to clear earlier rectangles
7118  Display->PlotDashedRect(2, TempRect);
7119  Display->Update(); // need to keep this since Update() not called for PlotSmallOutput as too slow
7120  }
7121 
7123 /* [Repeated from MouseDown] - The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
7124  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
7125  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
7126  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
7127  [New] - The same actions apply on MouseMove whether Copy or Cut selected from the menu. The X & Y mouse positions are checked and set to
7128  stay within the display area. Then the current selection H & V positions are stored in NewSelectBitmapHLoc & VLoc.
7129  These change continually while the mouse and the selection are moving, they are only read on MouseUp to retain the position that it then
7130  occupies. Clearand... is called finally to clear earlier selection displays.
7131 */
7132  {
7133  TrainController->LogEvent("MouseMove + Copy or CutMoving & SelectPickedUp");
7134  if(X < 0)
7135  X = 0; // ensure pointer stays within display area
7136  if(X > (MainScreen->Width - 1))
7137  X = MainScreen->Width - 1;
7138  if(Y < 0)
7139  Y = 0;
7140  if(Y > (MainScreen->Height - 1))
7141  Y = MainScreen->Height - 1;
7144  ClearandRebuildRailway(15); // plots SelectBitmap at the position given by NewSelectBitmapHLoc & ...VLoc
7145  }
7146 
7148  {
7149  TrainController->LogEvent("MouseMove + MoveTextOrGraphic & TextFoundFlag");
7151  NewHPos = TextOrUserGraphicGridVal * (div(NewHPos, TextOrUserGraphicGridVal).quot);
7153  NewVPos = TextOrUserGraphicGridVal * (div(NewVPos, TextOrUserGraphicGridVal).quot);
7154 
7155  TextHandler->TextPtrAt(26, TextItem)->HPos = NewHPos;
7156  TextHandler->TextPtrAt(27, TextItem)->VPos = NewVPos;
7158  }
7159 
7161  {
7162  TrainController->LogEvent("MouseMove + MoveTextOrGraphic & UserGraphicFoundFlag");
7164  NewHPos = TextOrUserGraphicGridVal * (div(NewHPos, TextOrUserGraphicGridVal).quot);
7166  NewVPos = TextOrUserGraphicGridVal * (div(NewVPos, TextOrUserGraphicGridVal).quot);
7167 
7171  }
7172  }
7173  Utilities->CallLogPop(70);
7174  }
7175  catch(const Exception &e)
7176  {
7177  ErrorLog(22, e.Message);
7178  }
7179 }
7180 
7181 // ---------------------------------------------------------------------------
7182 void __fastcall TInterface::MainScreenMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
7183 {
7184 /* [Repeated from MouseDown] - When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
7185  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
7186  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
7187  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
7188  selected rectangle.
7189  [Repeated from MouseMove] - At this point the select starting position has been defined in SelectStartPair, and the current mouse position is defined (wrt whole
7190  railway) in HLoc & VLoc from the screen positions X & Y by GetTrackLocsFromScreenPos. Both are incremented so that the rectangle
7191  includes the current point (if no mouse movement at all occurs then a 1 x 1 rectangle is displayed). Limits are set to prevent the
7192  displayed rectangle extending off screen. Edges are set at 60 & 36 rather than 59 & 35 because the defined rectangle excludes the
7193  rightmost and bottom HLoc & VLoc values, if 59 & 35 were used the right & bottom screen edges wouldn't be reached. A TRect is then
7194  defined from SelectStartPair and the HLoc/VLoc values, Clearand... called to clear earlier rectangles, and a dashed edge drawn round
7195  the selection.
7196  [New] This function can take some time so an houglass cursor is displayed. The rectangle is fully defined, so the final screen X & Y
7197  values are translated into HLoc & VLoc values (wrt whole railway) and SelectEndPair set using them. The rectangle can be defined in any
7198  direction, so the end points may be before or after the starting points for both horizontal and vertical directions. Therefore the
7199  rectangle that will be used subsequently - SelectRect - is defined from SelectStart and SelectEnd allowing for any direction. Screen
7200  limits are set as during MouseMove, and a dashed edge drawn as before. Then a check is made to see if the final rectangle has any area,
7201  and if not 'Select' mode is kept and the function ends so that a new rectangle can be drawn, otherwise new menu items Cut, Copy & Delete,
7202  are enabled. Now the SelectBitmap is made ready by filling with white prior to the track bitmaps being copied. If this isn't done the
7203  track bitmaps are loaded from the top left hand corner and the rest becomes black - not what is wanted! The SelectVector (defined in
7204  TrackUnit) is then loaded with the elements enclosed by the rectangle, top to bottom and left to right, active track elements first then
7205  inactive track elements. Empty squares are ignored as are default (erased) elements. Now the SelectVector is read and the corresponding
7206  element bitmaps transferred to SelectBitmap in the appropriate positions, then a dashed border added. Finally the cursor is changed back
7207  to an arrow.
7208 */
7209  try
7210  {
7211  TrainController->LogEvent("MainScreenMouseUp," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7212  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseUp," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7213  WholeRailwayMoving = false; // added at v2.1.0
7214  Screen->Cursor = TCursor(-2); // Arrow; (to reset from four arrows when moving) added at v2.1.0
7216  {
7217  TrainController->LogEvent("MouseUp + TrackSelecting + mbLeftDown");
7218  Screen->Cursor = TCursor(-11); // Hourglass;
7219  int EndHLoc, EndVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7220  Track->GetTrackLocsFromScreenPos(3, EndHLoc, EndVLoc, X, Y); // these values don't allow for offsets so add in later
7221 // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7222 // rightmost point and the VLoc value of the bottommost point
7223  if(EndHLoc >= StartHLoc)
7224  EndHLoc++;
7225  else
7226  StartHLoc++;
7227  if(EndVLoc >= StartVLoc)
7228  EndVLoc++;
7229  else
7230  StartVLoc++;
7231  if(StartHLoc >= EndHLoc)
7232  {
7233  SelectRect.left = EndHLoc;
7234  SelectRect.right = StartHLoc;
7235  }
7236  else
7237  {
7238  SelectRect.left = StartHLoc;
7239  SelectRect.right = EndHLoc;
7240  }
7241  if(StartVLoc >= EndVLoc)
7242  {
7243  SelectRect.top = EndVLoc;
7244  SelectRect.bottom = StartVLoc;
7245  }
7246  else
7247  {
7248  SelectRect.top = StartVLoc;
7249  SelectRect.bottom = EndVLoc;
7250  }
7255  if(SelectRect.left - Display->DisplayOffsetH < 0)
7257  if(SelectRect.top - Display->DisplayOffsetV < 0)
7262  if((SelectRect.top == SelectRect.bottom) || (SelectRect.left == SelectRect.right))
7263  {
7264  SelectionValid = false;
7266  mbLeftDown = false;
7267  Screen->Cursor = TCursor(-2); // Arrow;
7268  Utilities->CallLogPop(71);
7269  return; // no rectangle
7270  }
7271  else
7272  {
7273  ReselectMenuItem->Enabled = false;
7274  CutMenuItem->Enabled = true;
7275  CopyMenuItem->Enabled = true;
7276  FlipMenuItem->Enabled = true;
7277  MirrorMenuItem->Enabled = true;
7278  RotRightMenuItem->Enabled = true;
7279  RotLeftMenuItem->Enabled = true;
7280  RotateMenuItem->Enabled = true;
7281  PasteMenuItem->Enabled = false;
7282 // PasteWithAttributesMenuItem->Enabled = false; //new menu item for v2.2.0 only enabled after cutting
7283  DeleteMenuItem->Enabled = true;
7284  if(Track->IsTrackFinished())
7285  SelectLengthsMenuItem->Enabled = true; // only permit if finished because reverts to DistanceStart
7286  else
7287  SelectLengthsMenuItem->Enabled = false; // and that can only be used if track linked
7288  SelectBiDirPrefDirsMenuItem->Visible = false;
7289  CancelSelectionMenuItem->Enabled = true;
7290  // set SelectBitmap
7291  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
7292  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
7293 
7294  // fill it with transparent white (i.e. use Draw) else graphics all plot from top left hand corner
7295  for(int H = 0; H < (SelectBitmap->Width) / 16; H++)
7296  {
7297  for(int V = 0; V < (SelectBitmap->Height) / 16; V++)
7298  {
7299  SelectBitmap->Canvas->Draw(H * 16, V * 16, RailGraphics->bmSolidBgnd);
7300  // NB in above if use bmTransparent it ISN'T transparent, but if use the non-transparent bmSolidBgnd it IS transparent
7301  // presumably superimposing a transparent bitmap onto a transparent bitmap makes the result non-transparent!
7302  }
7303  }
7304 
7305  // store elements in Track->SelectVector, active elements first then inactive so active element plotted first during paste
7306  // clear the vector first
7308  TTrackElement TempElement; // default element
7309  bool FoundFlag;
7310  for(int x = SelectRect.left; x < SelectRect.right; x++)
7311  {
7312  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
7313  {
7314  int ATVecPos = Track->GetVectorPositionFromTrackMap(2, x, y, FoundFlag);
7315  if(FoundFlag)
7316  {
7317  TempElement = Track->TrackElementAt(440, ATVecPos);
7318  if(TempElement.SpeedTag > 0)
7319  Track->SelectPush(TempElement); // don't store erase elements
7320  }
7321  }
7322  }
7323  // now store inactive elements
7324  for(int x = SelectRect.left; x < SelectRect.right; x++)
7325  {
7326  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
7327  {
7328  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(2, x, y, FoundFlag);
7329  if(FoundFlag)
7330  {
7331  TempElement = Track->InactiveTrackElementAt(30, IATVecPair.first);
7332  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
7333  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
7334  {
7335  TempElement = Track->InactiveTrackElementAt(31, IATVecPair.second);
7336  Track->SelectPush(TempElement);
7337  }
7338  }
7339  }
7340  }
7341  // store text items
7342  int LowSelectHPos = SelectRect.left * 16;
7343  int HighSelectHPos = SelectRect.right * 16;
7344  int LowSelectVPos = SelectRect.top * 16;
7345  int HighSelectVPos = SelectRect.bottom * 16;
7346  TextHandler->SelectTextVector.clear();
7347  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
7348  {
7349  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
7350  {
7351  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
7352  HighSelectVPos))
7353  {
7354  // have to create a new TextItem in order to create a new Font object
7355  // BUT: only create new items where they don't appear as named location names
7356  // in SelectVector, since those names shouldn't be copied or pasted.
7357  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
7358  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
7359  bool SelectVectorNamedElement = false;
7360  AnsiString SelectTextString; // new at v2.2.0
7361  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
7362  {
7363  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
7364  {
7365  SelectVectorNamedElement = true;
7366  break;
7367  }
7368  }
7369  if(SelectVectorNamedElement) // changed at v2.2.0
7370  {
7371  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
7372  }
7373  else // new at v2.2.0
7374  {
7375  SelectTextString = TextPtr->TextString;
7376  }
7377  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
7378  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
7379  }
7380  }
7381  }
7382  // store graphic items, but first clear SelectGraphicVector
7383  Track->SelectGraphicVector.clear();
7384  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
7385  {
7386  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
7387  UserGraphicPtr++)
7388  {
7389  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) &&
7390  (UserGraphicPtr->VPos >= LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
7391  {
7392  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
7393  }
7394  }
7395  }
7396 // new method - direct copying of existing selection so text included
7397  TRect Dest(0, 0, SelectBitmap->Width, SelectBitmap->Height);
7398  TRect Source(((SelectRect.left - Display->DisplayOffsetH) * 16), ((SelectRect.top - Display->DisplayOffsetV) * 16),
7399  ((SelectRect.right - Display->DisplayOffsetH) * 16), ((SelectRect.bottom - Display->DisplayOffsetV) * 16));
7400  SelectBitmap->Canvas->CopyRect(Dest, MainScreen->Canvas, Source);
7401  SelectionValid = true;
7402  }
7403  Screen->Cursor = TCursor(-2); // Arrow;
7404  }
7405 
7407  {
7408  TrainController->LogEvent("MouseUp + PrefDirSelecting + mbLeftDown");
7409  Screen->Cursor = TCursor(-11); // Hourglass;
7410 
7411  int EndHLoc, EndVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7412  Track->GetTrackLocsFromScreenPos(6, EndHLoc, EndVLoc, X, Y); // these values don't allow for offsets so add in later
7413 // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7414 // rightmost point and the VLoc value of the bottommost point
7415  if(EndHLoc >= StartHLoc)
7416  EndHLoc++;
7417  else
7418  StartHLoc++;
7419  if(EndVLoc >= StartVLoc)
7420  EndVLoc++;
7421  else
7422  StartVLoc++;
7423  if(StartHLoc >= EndHLoc)
7424  {
7425  SelectRect.left = EndHLoc;
7426  SelectRect.right = StartHLoc;
7427  }
7428  else
7429  {
7430  SelectRect.left = StartHLoc;
7431  SelectRect.right = EndHLoc;
7432  }
7433  if(StartVLoc >= EndVLoc)
7434  {
7435  SelectRect.top = EndVLoc;
7436  SelectRect.bottom = StartVLoc;
7437  }
7438  else
7439  {
7440  SelectRect.top = StartVLoc;
7441  SelectRect.bottom = EndVLoc;
7442  }
7447  if(SelectRect.left - Display->DisplayOffsetH < 0)
7449  if(SelectRect.top - Display->DisplayOffsetV < 0)
7454  if((SelectRect.top == SelectRect.bottom) || (SelectRect.left == SelectRect.right))
7455  {
7457  mbLeftDown = false;
7458  Screen->Cursor = TCursor(-2); // Arrow;
7459  Utilities->CallLogPop(1551);
7460  return; // no rectangle
7461  }
7462  else
7463  {
7464  SelectBiDirPrefDirsMenuItem->Enabled = true;
7465  CancelSelectionMenuItem->Enabled = true;
7466  // don't need SelectBitmap for PrefDir selection
7467 
7468  // store active elements in Track->SelectVector, ignore inactive elements
7469  // clear the vector first
7471  TTrackElement TempElement; // default element
7472  bool FoundFlag;
7473  for(int x = SelectRect.left; x < SelectRect.right; x++)
7474  {
7475  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
7476  {
7477  int ATVecPos = Track->GetVectorPositionFromTrackMap(43, x, y, FoundFlag);
7478  if(FoundFlag)
7479  {
7480  TempElement = Track->TrackElementAt(729, ATVecPos);
7481  if(TempElement.SpeedTag > 0)
7482  Track->SelectPush(TempElement); // don't store erase elements
7483  }
7484  }
7485  }
7486  }
7487  Screen->Cursor = TCursor(-2); // Arrow;
7488  }
7489 
7491 /* [Repeated from MouseDown] - The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
7492  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
7493  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
7494  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
7495  [Repeated from MouseMove] - The same actions apply on MouseMove whether Copy or Cut selected from the menu. The X & Y mouse positions are checked and set to
7496  stay within the display area. Then the current selection H & V positions are stored in NewSelectBitmapHLoc & VLoc.
7497  These change continually while the mouse and the selection are moving, they are only read on MouseUp to retain the position that it then
7498  occupies. Clearand... is called finally to clear earlier selection displays.
7499  [New] - The only action here is to transfer the values of NewSelectBitmapHLoc & VLoc to SelectBitmapHLoc & VLoc so that the selection
7500  stays in the same position (Clearand... checks whether the mouse is moving (both mbLeftDown & SelectPickedUp true) or stopped (either
7501  mbLeftDown or SelectPickedUp false) and uses NewSelectBitmapHLoc & VLoc or SelectBitmapHLoc & SelectBitmapVLoc respectively.
7502 */
7503  {
7504  TrainController->LogEvent("MouseUp + Copy or CutMoving + mbLeftDown + SelectPickedUp");
7507  }
7508 
7509  mbLeftDown = false;
7510  Track->CalcHLocMinEtc(11);
7511  Utilities->CallLogPop(72);
7512  }
7513  catch(const Exception &e)
7514  {
7515  ErrorLog(23, e.Message);
7516  }
7517 }
7518 
7519 // ---------------------------------------------------------------------------
7520 
7521 void __fastcall TInterface::MasterClockTimer(TObject *Sender)
7522 {
7523  try
7524  {
7525  // don't call LogEvent here as would occur too often
7526  // have to allow in zoomout mode
7527  if(ErrorLogCalledFlag)
7528  return; // don't continue after an error
7529 
7530  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MasterClockTimer");
7531  // put counter outside Clock2 as that may be missed
7532  LCResetCounter++;
7533 // this checks LCs every 20 clock ticks (1 sec) & raises barriers if no route & no train present, to avoid delays due to too frequent calls
7534  if(LCResetCounter > 19)
7535  LCResetCounter = 0;
7537  if(WarningFlashCount > 4)
7538  WarningFlashCount = 0;
7539  if(WarningFlashCount == 0)
7540  {
7542  }
7543 
7544  if(Utilities->CallLog.size() > 50) // use CTRL ALT 2 to see CallLogSize as program operates
7545  {
7546  throw Exception("Warning - Utilities->CallLog contains more than 50 items"); // check before clock stopped
7547  }
7548 
7550  // stopped during 'Paused', when modal windows appear - Popup menu & ShowMessage, and at other times
7551  {
7552  // RestartTime is TTClockTime when operation pauses (timetable start time initially),
7553  // BaseTime is CurrentDateTime() when operation restarts
7554 
7555 // clock speed multiplier
7556  double RealTimeDouble = double(TDateTime::CurrentDateTime() - TrainController->BaseTime);
7557  TrainController->TTClockTime = TDateTime(TTClockSpeed * RealTimeDouble) + TrainController->RestartTime;
7558 // TrainController->TTClockTime = TDateTime::CurrentDateTime() - TrainController->BaseTime + TrainController->RestartTime;
7559  }
7560 
7561  TotalTicks++;
7563  {
7564  MissedTicks++;
7565  Utilities->CallLogPop(774);
7566  return;
7567  }
7568  Utilities->Clock2Stopped = true; //don't allow overlapping calls
7569  ClockTimer2(0);
7570  Utilities->Clock2Stopped = false;
7571  Utilities->CallLogPop(73);
7572  }
7573  catch(const Exception &e)
7574  {
7575  ErrorLog(24, e.Message);
7576  }
7577 }
7578 
7579 // ---------------------------------------------------------------------------
7580 
7581 void TInterface::ClockTimer2(int Caller)
7582 {
7583 // called every 50mSec
7584  try
7585  {
7586  // have to allow in zoomout mode
7587  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ClockTimer2");
7588 
7589  // dropped at 2.0.0 because RestoreFocusPanel->SetFocus(); hides the help screen
7590  // If a button holds focus then all that is needed is to click the screen and the arrow keys work correctly
7591 
7592 /* Dropped when new .chm help file introduced at v2.0.0 - this hid it after ~20ms. Replaced by a new section in
7593  MainScreenMouseDown where focus restored to screen when click anywhere on screen, allowing navigation keys to
7594  move screen when clicked if focus had been captured by another panel when these keys just cycle through the panel buttons
7595 
7596  bool FocusRestoreAllowedFlag = true; //added at v1.3.0
7597 
7598  if(TextBox->Focused() || DistanceBox->Focused() || SpeedLimitBox->Focused() || LocationNameTextBox->Focused() || MileEdit->Focused() || ChainEdit->Focused() || YardEdit->Focused() ||
7599  SpeedEditBox2->Focused() || LocationNameComboBox->Focused() || AddSubMinsBox->Focused() || SpeedEditBox->Focused() || PowerEditBox->Focused() || OneEntryTimetableMemo->Focused() ||
7600  AddPrefDirButton->Focused()) //Added at v1.3.0. If any of these has focus then they keep it until they release it. AddPrefDirButton is included as it should keep focus
7601  FocusRestoreAllowedFlag = false; //when it has it - eases the setting of PrefDirs, also this button becomes disabled after use so focus returns to Interface naturally
7602 
7603  if(!Focused() && FocusRestoreAllowedFlag && (GetAsyncKeyState(VK_LBUTTON) >= 0) && (GetAsyncKeyState(VK_RBUTTON) >= 0)) //condition added at v1.3.0 to ensure focus returned to
7604  //Interface (so arrow keys work to move screen) & not left at any of the buttons or other Windows controls
7605  //include the Windows API functions to test that the mouse buttons are not down (strictly only need left but user may have mapped the left onto the right so test both) - if not
7606  //tested then don't always respond to button clicks on navigation and other buttons because the focus can be grabbed back from the button by RestoreFocusPanel before the button
7607  //can respond (takes about 200mSec from click to response) a delay is also included to doubly avoid the button losing focus as above
7608  {
7609  ClockTimer2Count++; //doesn't matter what value it starts at on first use, it will soon revert to 0
7610  if(ClockTimer2Count > 10) ClockTimer2Count = 0; //half second delay
7611  if(ClockTimer2Count == 0)
7612  {
7613  RestoreFocusPanel->Visible = true;
7614  RestoreFocusPanel->Enabled = true;
7615  RestoreFocusPanel->BringToFront();
7616  //RestoreFocusPanel->SetFocus(); //to remove focus from anything else
7617  RestoreFocusPanel->Enabled = false; //to remove focus from RestoreFocusPanel & return it to Interface
7618  RestoreFocusPanel->Visible = false;
7619  }
7620  }
7621  else ClockTimer2Count = 0; //reset to 0 so ensure full delay occurs before RestoreFocusPanel grabs focus from anything else
7622 */
7623 
7624  CallLogTickerLabel->Caption = Utilities->CallLog.size(); // diagnostic test function to ensure all CallLogs are popped - visibility
7625  // toggled by 'Ctrl Alt 2' when Interface form has focus
7626 
7627  // set current time
7628  TDateTime Now = TrainController->TTClockTime;
7629 
7634 
7635  if(OperatorActionPanel->Visible)
7639  TrainController->OpActionPanelHintDelayCounter = 80; // new at v2.2.0
7640 
7641  TrainController->RandomFailureCounter++; // new at v2.4.0 counts up for 53 seconds then resets
7643  {
7645  }
7646 
7647 // Update Displayed Clock - resets to 0 at 96hours
7649 
7650 // Below added at v2.1.0 to ensure WholeRailwayMoving flag reset when not moving (when rh mouse button up) as sometimes misses
7651 // MouseUp events, probably due to a clash between a moving event and a mouse up event. Note that checks that both mouse buttons are up because
7652 // function only checks the physical buttons, not the logical buttons. Most sig bit of return value set form key down.
7653  if(WholeRailwayMoving && (GetAsyncKeyState(VK_LBUTTON) >= 0) && (GetAsyncKeyState(VK_RBUTTON) >= 0))
7654  {
7655  WholeRailwayMoving = false;
7656  Screen->Cursor = TCursor(-2); // Arrow
7657  }
7658 
7659 // save session if required
7660  if(SaveSessionFlag)
7661  {
7662  SaveSession(0);
7663  SaveSessionFlag = false;
7664  }
7665 // load session if required
7666  if(LoadSessionFlag)
7667  {
7668  if(ClearEverything(3))
7669  {
7670  LoadSession(0);
7671  }
7672  LoadSessionFlag = false;
7673  }
7674 
7675 // check if any LCs need barriers raising
7676 
7678  {
7680  {
7681  for(int x = Track->BarriersDownVector.size() - 1; x >= 0; x--)
7682  {
7683  bool TrainPresent = false;
7685  TrainPresent))
7686  {
7687  if(TrainPresent)
7688  {
7689  Track->BarriersDownVector.at(x).TrainPassed = true;
7690  }
7691  }
7692  else
7693  {
7694  Track->LCChangeFlag = true;
7696  // check if have exceeded the allowance (3 minutes for a train having passed or 0 for not) and add it to the overall excess time
7697  TDateTime TempExcessLCDownTime;
7698  if(Track->BarriersDownVector.at(x).TrainPassed)
7699  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime - TDateTime(180.0 / 86400);
7700  else
7701  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime;
7702  if(TempExcessLCDownTime > TDateTime(0))
7703  TrainController->ExcessLCDownMins += (double(TempExcessLCDownTime) * 1440);
7704 
7705  CLC.StartTime = TrainController->TTClockTime; // reset these 3 members
7708  Track->SetLinkedLevelCrossingBarrierAttributes(0, CLC.HLoc, CLC.VLoc, 2); // set attr to 2 for changing state
7709  Track->ChangingLCVector.push_back(CLC);
7710  Track->BarriersDownVector.erase(Track->BarriersDownVector.begin() + x);
7711  }
7712  }
7713  }
7714  }
7715 // clear LCChangeFlag if no LCs changing
7716  if(Track->ChangingLCVector.empty())
7717  {
7718  Track->LCChangeFlag = false;
7719  }
7720 
7721 // remove any single route elements if operating, but only if not constructing a route, else if extending the single route
7722 // element it may be removed prior to conversion & cause an error
7723 
7724 // note that if a train enters at a continuation and a signal is next but one to the continuation then the route element at that
7725 // signal won't be removed because the train's LagElement is still -1 and trains only remove route elements when LagElement is > -1.
7726 // This also means that a preferred route can't be cancelled as it's under a train, but it's probably not worth adding a patch just for
7727 // this, it shouldn't interfere with operation.
7729  {
7730  bool ElementRemovedFlag = false; // introduced at v0.6 to avoid calling Clearand.... multiple times
7731  for(unsigned int x = 0; x < AllRoutes->AllRoutesSize(); x++)
7732  {
7733  if(AllRoutes->GetFixedRouteAt(187, x).PrefDirSize() == 1)
7734  {
7735  // only allow route element to be removed if not selected for a route start otherwise StartSelectionRouteID will be
7736  // set & will fail at convert
7738  {
7740  AllRoutes->RemoveRouteElement(20, PDE.HLoc, PDE.VLoc, PDE.GetELink());
7741  ElementRemovedFlag = true;
7742  TrainController->LogEvent("SingleRouteElementRemoved, H = " + AnsiString(PDE.HLoc) + ", V = " + AnsiString(PDE.VLoc));
7743  }
7744  }
7745  }
7746  if(!Display->ZoomOutFlag && ElementRemovedFlag)
7747  ClearandRebuildRailway(66); // if zoomed out ignore, will display correctly when zoom in
7748  // if leave the Zoomout condition out then the zoom out will spontaneously cancel and the track won't display because
7749  // PlotOutput returns if zoomed out, and the zoom out flag isn't reset until the end of Clearand.....
7750  // this was moved outside the for.. next.. loop in v0.6 as it could be called multiple times and slowed down operation (noticeable with a fast clock)
7751  }
7752 // stop clock if hover over a warning
7753  bool WH1 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog1->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog1->Width + OutputLog1->Left))
7754  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog1->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog1->Height + OutputLog1->Top))
7755  && OutputLog1->Caption != "";
7756  bool WH2 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog2->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog2->Width + OutputLog2->Left))
7757  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog2->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog2->Height + OutputLog2->Top))
7758  && OutputLog2->Caption != "";
7759  bool WH3 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog3->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog3->Width + OutputLog3->Left))
7760  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog3->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog3->Height + OutputLog3->Top))
7761  && OutputLog3->Caption != "";
7762  bool WH4 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog4->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog4->Width + OutputLog4->Left))
7763  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog4->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog4->Height + OutputLog4->Top))
7764  && OutputLog4->Caption != "";
7765  bool WH5 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog5->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog5->Width + OutputLog5->Left))
7766  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog5->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog5->Height + OutputLog5->Top))
7767  && OutputLog5->Caption != "";
7768  bool WH6 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog6->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog6->Width + OutputLog6->Left))
7769  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog6->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog6->Height + OutputLog6->Top))
7770  && OutputLog6->Caption != "";
7771  bool WH7 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog7->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog7->Width + OutputLog7->Left))
7772  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog7->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog7->Height + OutputLog7->Top))
7773  && OutputLog7->Caption != "";
7774  bool WH8 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog8->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog8->Width + OutputLog8->Left))
7775  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog8->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog8->Height + OutputLog8->Top))
7776  && OutputLog8->Caption != "";
7777  bool WH9 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog9->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog9->Width + OutputLog9->Left))
7778  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog9->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog9->Height + OutputLog9->Top))
7779  && OutputLog9->Caption != "";
7780  bool WH10 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog10->Left) &&
7781  (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog10->Width + OutputLog10->Left)) && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog10->Top) &&
7782  (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog10->Height + OutputLog10->Top)) && OutputLog10->Caption != "";
7783 
7784  if(WH1 || WH2 || WH3 || WH4 || WH5 || WH6 || WH7 || WH8 || WH9 || WH10)
7785  {
7786  if(!WarningHover)
7787  {
7788  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
7790  WarningHover = true;
7791  }
7792  }
7793  else if(WarningHover)
7794  {
7795  WarningHover = false;
7796  TrainController->BaseTime = TDateTime::CurrentDateTime();
7798  }
7799 
7800 // development panel - visibility toggled by 'Ctrl Alt 3' when Interface form has focus
7801  if(DevelopmentPanel->Visible)
7802  {
7803  int Position;
7804  TTrackElement TrackElement;
7805  AnsiString Type[15] =
7806  {"Simple", "Crossover", "Points", "Buffers", "Bridge", "SignalPost", "Continuation", "Platform", "GapJump", "FootCrossing", "Unused", "Concourse",
7807  "Parapet", "NamedNonStationLocation", "Erase"};
7808 
7809  int ScreenX = Mouse->CursorPos.x - MainScreen->ClientOrigin.x;
7810  int ScreenY = Mouse->CursorPos.y - MainScreen->ClientOrigin.y;
7811  int HLoc, VLoc;
7812  AnsiString MouseStr = "Posx: " + AnsiString(ScreenX) + "; Posy: " + AnsiString(ScreenY);
7813  DevelopmentPanel->Caption = CurDir + " " + MouseStr;
7814  Track->GetTrackLocsFromScreenPos(7, HLoc, VLoc, ScreenX, ScreenY);
7815  if(Track->FindNonPlatformMatch(1, HLoc, VLoc, Position, TrackElement))
7816  {
7817  DevelopmentPanel->Caption = MouseStr + "; TVPos: " + AnsiString(Position) + "; H: " + AnsiString(HLoc) + "; V: " + AnsiString(VLoc) +
7818  "; SpTg: " + AnsiString(TrackElement.SpeedTag) + "; Type: " + Type[TrackElement.TrackType] + "; Att: " + AnsiString(TrackElement.Attribute)
7819  + "; TrID: " + AnsiString(TrackElement.TrainIDOnElement) + "; TrID01: " + AnsiString(TrackElement.TrainIDOnBridgeTrackPos01) +
7820  "; TrID23: " + AnsiString(TrackElement.TrainIDOnBridgeTrackPos23) + "; " + TrackElement.LocationName + "; " +
7821  TrackElement.ActiveTrackElementName;
7822 // + "; OAHintCtr: " + TrainController->OpActionPanelHintDelayCounter;
7823  }
7824  }
7825 
7826 // highlight timetable entry if in tt mode (have to call this regularly so will scroll with the listbox)
7827  if(Level1Mode == TimetableMode)
7828  {
7829  if(!TimetableEditVector.empty() && (TTCurrentEntryPtr > 0))
7830  {
7832  }
7833  else
7834  {
7836  }
7837  }
7838 
7839 // set cursor
7841  {
7842  if(!TempCursorSet)
7843  {
7844  TempCursor = Screen->Cursor;
7845  TempCursorSet = true;
7846  }
7847  Screen->Cursor = TCursor(-11); // Hourglass
7848  }
7849  else
7850  {
7851  if(TempCursorSet)
7852  {
7853  Screen->Cursor = TempCursor;
7854  TempCursorSet = false;
7855  }
7856  }
7857 
7858  if(Level2OperMode == Operating)
7859  {
7860  TrainController->Operate(0); // ensure this called AFTER the single element route removal to ensure any single elements removed
7861  // prior to CallingOnAllowed being called (in UpdateTrain) as that sets a route from the stop signal
7863  {
7864  UpdateOperatorActionPanel(0); // new at v2.2.0 to update panel when train OpTimeToAct updated
7865  }
7866  TrainController->SignallerTrainRemovedOnAutoSigsRoute = false; // added at v1.3.0 to ensure doesn't persist beyone one call
7867  }
7868 
7869 // plot trains in ZoomOut mode & flash trains where attention needed alternately on & off at each call
7870 // by examining Flash
7871  if((Level1Mode == OperMode) && (Display->ZoomOutFlag))
7872  {
7874  }
7875 
7876 // Deal with any flashing graphics
7878  {
7879  FlashingGraphics(0, Now); // only call when WarningFlash changes
7880  if(Level1Mode == OperMode)
7881  {
7882  if(WarningFlash)
7883  {
7885  {
7886  CrashImage->Visible = true;
7887  }
7889  {
7890  DerailImage->Visible = true;
7891  }
7893  {
7894  SPADImage->Visible = true;
7895  }
7897  {
7898  TrainFailedImage->Visible = true;
7899  }
7901  {
7902  CallOnImage->Visible = true;
7903  }
7905  {
7906  SignalStopImage->Visible = true;
7907  }
7909  {
7910  BufferAttentionImage->Visible = true;
7911  }
7912  }
7913  else
7914  {
7915  CrashImage->Visible = false;
7916  DerailImage->Visible = false;
7917  SPADImage->Visible = false;
7918  TrainFailedImage->Visible = false;
7919  CallOnImage->Visible = false;
7920  SignalStopImage->Visible = false;
7921  BufferAttentionImage->Visible = false;
7922  }
7923  }
7924  else
7925  {
7926  CrashImage->Visible = false;
7927  DerailImage->Visible = false;
7928  SPADImage->Visible = false;
7929  TrainFailedImage->Visible = false;
7930  CallOnImage->Visible = false;
7931  SignalStopImage->Visible = false;
7932  BufferAttentionImage->Visible = false;
7933  }
7934  } // if(WarningFlashCount == 0)
7935  // set buttons etc as appropriate
7937  // if forced route cancellation flag set redisplay to clear the cancelled route
7939  {
7941  AllRoutes->RebuildRailwayFlag = false;
7942  }
7943  // deal with approach locking
7945  // deal with ContinuationAutoSigList
7947  // FloatingLabel function
7948  if((TrackInfoOnOffMenuItem->Caption == "Hide") || (TrainStatusInfoOnOffMenuItem->Caption == "Hide Status") ||
7949  (TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable"))
7950  {
7951  TrackTrainFloat(0);
7952  }
7953  else
7954  {
7955  FloatingPanel->Visible = false;
7956  }
7957  // PerformanceLog check function
7958 /*
7959  if(IsPerformancePanelObscuringFloatingLabel(0) && (ShowPerformancePanel))
7960  {
7961  PerformancePanel->Visible = false;
7962  }
7963  else
7964  {
7965 */
7967  {
7968  PerformancePanel->Visible = true;
7969  }
7970  else
7971  {
7972  PerformancePanel->Visible = false;
7973  }
7974 
7976  {
7977  OperatorActionPanel->Visible = true;
7978  }
7979  else
7980  {
7981  OperatorActionPanel->Visible = false;
7982  }
7983 
7984 // }
7985 
7986  // check if a moving train is present on a route-under-construction start element & cancel it if so
7987  if(RouteMode == RouteContinuing)
7988  {
7989  bool FoundFlag;
7990  int RouteStartVecPos;
7991  if(AutoSigsFlag)
7993  FoundFlag);
7994  else if(ConsecSignalsRoute)
7995  RouteStartVecPos = Track->GetVectorPositionFromTrackMap(8, (SigRouteStartMarker->GetHPos()) / 16, (SigRouteStartMarker->GetVPos()) / 16,
7996  FoundFlag);
7997  else
7999  FoundFlag);
8000  if(FoundFlag && (RouteStartVecPos > -1))
8001  {
8002  TTrackElement TrackElement = Track->TrackElementAt(485, RouteStartVecPos);
8003  if(TrackElement.TrainIDOnElement > -1)
8004  {
8005  if(!(TrainController->TrainVectorAtIdent(2, TrackElement.TrainIDOnElement).Stopped()))
8006  {
8008  // replot train as above erases the front element of the train
8010  }
8011  }
8012  }
8013  }
8014  Utilities->CallLogPop(81);
8015  }
8016  catch(const Exception &e)
8017  {
8018  ErrorLog(25, e.Message);
8019  }
8020 }
8021 
8022 // ---------------------------------------------------------------------------
8023 
8024 void __fastcall TInterface::CallingOnButtonClick(TObject *Sender)
8025 {
8026  try
8027  {
8028  TrainController->LogEvent("CallingOnButtonClick");
8029  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CallingOnButtonClick");
8030  if(CallingOnButton->Down)
8031  {
8032  // CallingOnButton->Down = true;
8033  InfoPanel->Visible = true;
8034  InfoPanel->Caption = "CALLING ON: Select signal for call on";
8035  }
8036  else
8037  {
8038  // CallingOnButton->Down = false;
8040  }
8041  AutoRouteStartMarker->PlotOriginal(29, Display); // if overlay not plotted will ignore
8042  SigRouteStartMarker->PlotOriginal(30, Display); // if overlay not plotted will ignore
8043  NonSigRouteStartMarker->PlotOriginal(31, Display); // if overlay not plotted will ignore
8044  CallingOnButton->Enabled = false;
8045 // added at v1.3.0 to ensure doesn't retain focus - will be re-enabled during ClockTimer2 (in SetSaveMenuAndButtons) if required
8046  Utilities->CallLogPop(82);
8047  }
8048  catch(const Exception &e)
8049  {
8050  ErrorLog(26, e.Message);
8051  }
8052 }
8053 
8054 // ---------------------------------------------------------------------------
8055 void __fastcall TInterface::ScreenLeftButtonClick(TObject *Sender)
8056 {
8057  try
8058  {
8059  // have to allow in zoomout mode
8060  TrainController->LogEvent("ScreenLeftButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8061  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenLeftButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8062  Screen->Cursor = TCursor(-11); // Hourglass;
8063  ScreenLeftButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
8064  if(!Display->ZoomOutFlag)
8065  {
8066  if(CtrlKey)
8067  {
8068  Display->DisplayOffsetH -= 2;
8069  }
8070  else if(ShiftKey)
8071  {
8073  }
8074  else
8075  {
8077  }
8080  {
8082  }
8083  }
8084  else
8085  {
8086  if(CtrlKey)
8087  {
8089  }
8090  else if(ShiftKey)
8091  {
8093  }
8094  else
8095  {
8097  }
8098  Display->ClearDisplay(0);
8101  Track->PlotSmallRedGap(0);
8102  }
8103  ScreenLeftButton->Enabled = true;
8104  Screen->Cursor = TCursor(-2); // Arrow
8105  Utilities->CallLogPop(83);
8106  }
8107  catch(const Exception &e)
8108  {
8109  ErrorLog(27, e.Message);
8110  }
8111 }
8112 // ---------------------------------------------------------------------------
8113 
8114 void __fastcall TInterface::ScreenRightButtonClick(TObject *Sender)
8115 {
8116  try
8117  {
8118  // have to allow in zoomout mode
8119  TrainController->LogEvent("ScreenRightButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8120  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenRightButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8121  Screen->Cursor = TCursor(-11); // Hourglass;
8122  ScreenRightButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
8123  if(!Display->ZoomOutFlag)
8124  {
8125  if(CtrlKey)
8126  {
8127  Display->DisplayOffsetH += 2;
8128  }
8129  else if(ShiftKey)
8130  {
8132  }
8133  else
8134  {
8136  }
8139  {
8141  }
8142  }
8143  else
8144  {
8145  if(CtrlKey)
8146  {
8148  }
8149  else if(ShiftKey)
8150  {
8152  }
8153  else
8154  {
8156  }
8157  Display->ClearDisplay(1);
8160  Track->PlotSmallRedGap(1);
8161  }
8162  ScreenRightButton->Enabled = true;
8163  Screen->Cursor = TCursor(-2); // Arrow
8164  Utilities->CallLogPop(84);
8165  }
8166  catch(const Exception &e)
8167  {
8168  ErrorLog(28, e.Message);
8169  }
8170 }
8171 // ---------------------------------------------------------------------------
8172 
8173 void __fastcall TInterface::ScreenDownButtonClick(TObject *Sender)
8174 {
8175  try
8176  {
8177  // have to allow in zoomout mode
8178  TrainController->LogEvent("ScreenDownButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8179  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenDownButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8180  Screen->Cursor = TCursor(-11); // Hourglass;
8181  ScreenDownButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
8182  // BUT - it does prevent it from retaining focus - so can use the cursor keys to scroll the display without being captured by the buttons
8183  if(!Display->ZoomOutFlag)
8184  {
8185  if(CtrlKey)
8186  {
8187  Display->DisplayOffsetV += 2;
8188  }
8189  else if(ShiftKey)
8190  {
8192  }
8193  else
8194  {
8196  }
8199  {
8201  }
8202  }
8203  else
8204  {
8205  if(CtrlKey)
8206  {
8208  }
8209  else if(ShiftKey)
8210  {
8212  }
8213  else
8214  {
8216  }
8217  Display->ClearDisplay(2);
8220  Track->PlotSmallRedGap(2);
8221  }
8222  ScreenDownButton->Enabled = true;
8223  Screen->Cursor = TCursor(-2); // Arrow
8224  Utilities->CallLogPop(85);
8225  }
8226  catch(const Exception &e)
8227  {
8228  ErrorLog(29, e.Message);
8229  }
8230 }
8231 // ---------------------------------------------------------------------------
8232 
8233 void __fastcall TInterface::ScreenUpButtonClick(TObject *Sender)
8234 {
8235  try
8236  {
8237  // have to allow in zoomout mode
8238  TrainController->LogEvent("ScreenUpButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8239  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenUpButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8240  Screen->Cursor = TCursor(-11); // Hourglass;
8241  ScreenUpButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
8242  if(!Display->ZoomOutFlag)
8243  {
8244  if(CtrlKey)
8245  {
8246  Display->DisplayOffsetV -= 2;
8247  }
8248  else if(ShiftKey)
8249  {
8251  }
8252  else
8253  {
8255  }
8258  {
8260  }
8261  }
8262  else
8263  {
8264  if(CtrlKey)
8265  {
8267  }
8268  else if(ShiftKey)
8269  {
8271  }
8272  else
8273  {
8275  }
8276  Display->ClearDisplay(3);
8279  Track->PlotSmallRedGap(3);
8280  }
8281  ScreenUpButton->Enabled = true;
8282  Screen->Cursor = TCursor(-2); // Arrow
8283  Utilities->CallLogPop(86);
8284  }
8285  catch(const Exception &e)
8286  {
8287  ErrorLog(30, e.Message);
8288  }
8289 }
8290 // ---------------------------------------------------------------------------
8291 
8292 void __fastcall TInterface::ZoomButtonClick(TObject *Sender)
8293 {
8294  try
8295  {
8296  // have to allow in zoomout mode
8297  TrainController->LogEvent("ZoomButtonClick");
8298  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ZoomButtonClick");
8299  Screen->Cursor = TCursor(-11); // Hourglass;
8300  ZoomButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
8301  if(Display->ZoomOutFlag) // i.e resume zoomed in view
8302  {
8303  TrainController->LogEvent("ZoomButtonClick + ZoomOutFlag");
8304 // TLevel2OperMode TempLevel2OperMode = Level2OperMode;
8305  if(Level1Mode == BaseMode)
8306  {
8307  InfoPanel->Visible = false; // reset infopanel in case not set later
8308  InfoPanel->Caption = "";
8309  SetLevel1Mode(18);
8310  }
8311  else if(Level1Mode == TrackMode)
8312  {
8313  InfoPanel->Visible = false; // reset infopanel in case not set later
8314  InfoPanel->Caption = "";
8315  // set edit menu items
8317  SetLevel2TrackMode(33); // revert to earlier track mode from zoom
8318  }
8319  else if(Level1Mode == PrefDirMode)
8320  {
8322  SetLevel1Mode(19); // to redisplay infopanel caption "...select start..."
8323  else
8324  SetLevel2PrefDirMode(4); // revert to PrefDirContinuing PrefDir mode
8325  }
8326 // else if(Level1Mode == TrackMode) SetLevel1Mode();//just revert to basic track mode from zoom
8327 // else if(Level1Mode == PrefDirMode) SetLevel1Mode();//just revert to basic PrefDir mode from zoom
8328  else if(Level1Mode == TimetableMode)
8329  {
8330  InfoPanel->Visible = false;
8331  }
8332  // Don't include OperMode or RestartSessionOperMode as they reset the performance file
8333  else if(Level2OperMode == Operating) // similar to SetLevel2OperMode but without resetting BaseTime
8334  {
8335  OperateButton->Enabled = true;
8336  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
8337  ExitOperationButton->Enabled = true;
8339  }
8340  else if(Level2OperMode == Paused) // similar to SetLevel2OperMode but without resetting RestartTime
8341  {
8342  OperateButton->Enabled = true;
8343  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
8344  ExitOperationButton->Enabled = true;
8345  TTClockAdjButton->Enabled = true;
8348  }
8349  else if(Level2OperMode == PreStart)
8350  {
8351  OperateButton->Enabled = true;
8352  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
8353  ExitOperationButton->Enabled = true;
8354  TTClockAdjButton->Enabled = true;
8356  }
8357  Display->ZoomOutFlag = false; // reset this after level modes called so gap flash stays set if set to begin with
8359  ClearandRebuildRailway(43); // need to call this after ZoomOutFlag reset to display track, even if Clearand... already called
8360  // earlier during level mode setting - because until ZoomOutFlag reset PlotOutput plots nothing
8361  }
8362  else // set zoomed out view
8363  {
8364  TrainController->LogEvent("ZoomButtonClick + != ZoomOutFlag");
8365  Display->ZoomOutFlag = true;
8367  FileMenu->Enabled = false;
8368  ModeMenu->Enabled = false;
8369  EditMenu->Enabled = false;
8370  TextBox->Visible = false;
8371  LocationNameTextBox->Visible = false;
8372  TTClockAdjButton->Enabled = false;
8373 // DisablePanelsStoreMainMenuStates();//ensure Display->ZoomOutFlag set true before calling
8374  // start assuming normal view is at centre of ZoomOut & calc excesses at each side
8375  int OVOffH_NVCentre = Display->DisplayOffsetH - (1.5 * Utilities->ScreenElementWidth);
8376 // start zoomout centre at DisplayOffsetH + 30 - zoomout width/2 = -(1.5 * 60)
8377  int LeftExcess = OVOffH_NVCentre - Track->GetHLocMin();
8378  int RightExcess = Track->GetHLocMax() - OVOffH_NVCentre - ((4 * Utilities->ScreenElementWidth) - 1);
8379  if((LeftExcess > 0) && (RightExcess > 0))
8380  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre;
8381  else if((LeftExcess > 0) && (RightExcess <= 0))
8382  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre + ((RightExcess) / (Utilities->ScreenElementWidth / 2)) *
8383  (Utilities->ScreenElementWidth / 2); // normalise to nearest screen
8384  else if((LeftExcess <= 0) && (RightExcess > 0))
8385  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre - ((LeftExcess) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2);
8386  else
8387  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre; // no excess at either side, so display in centre
8388 
8389  int OVOffV_NVCentre = Display->DisplayOffsetV - (1.5 * Utilities->ScreenElementHeight);
8390  int TopExcess = OVOffV_NVCentre - Track->GetVLocMin();
8391  int BotExcess = Track->GetVLocMax() - OVOffV_NVCentre - ((4 * Utilities->ScreenElementHeight) - 1);
8392  if((TopExcess > 0) && (BotExcess > 0))
8393  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre;
8394  else if((TopExcess > 0) && (BotExcess <= 0))
8395  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre + ((BotExcess) / (Utilities->ScreenElementHeight / 2)) *
8396  (Utilities->ScreenElementHeight / 2); // normalise to nearest half screen
8397  else if((TopExcess <= 0) && (BotExcess > 0))
8398  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre - ((TopExcess) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2);
8399  else
8400  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre; // no excess at either side, so display in centre
8401 
8402  Display->ClearDisplay(4);
8406  Track->PlotSmallRedGap(4);
8407  ZoomButton->Glyph->LoadFromResourceName(0, "ZoomIn");
8408  }
8409  Screen->Cursor = TCursor(-2); // Arrow
8410  ZoomButton->Enabled = true; // restore, see above
8411  Utilities->CallLogPop(87);
8412  }
8413  catch(const Exception &e)
8414  {
8415  ErrorLog(31, e.Message);
8416  }
8417 }
8418 // ---------------------------------------------------------------------------
8419 
8420 void __fastcall TInterface::HomeButtonClick(TObject *Sender)
8421 {
8422  try
8423  {
8424  // have to allow in zoomout mode
8425  TrainController->LogEvent("HomeButtonClick");
8426  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",HomeButtonClick");
8427  Screen->Cursor = TCursor(-11); // Hourglass;
8428  HomeButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
8429  if(!Display->ZoomOutFlag) // zoomed in mode
8430  {
8431  TrainController->LogEvent("HomeButtonClick + zoomed in mode");
8435  {
8437  }
8438  }
8439  else
8440  {
8441  // zoomed out mode
8442  // start assuming normal view is at centre of ZoomOut & calc excesses at each side
8443  TrainController->LogEvent("HomeButtonClick + zoomed out mode");
8445  Display->ClearDisplay(9);
8448  Track->PlotSmallRedGap(5);
8449  }
8450  Screen->Cursor = TCursor(-2); // Arrow
8451  HomeButton->Enabled = true; // restore, see above
8452  Utilities->CallLogPop(88);
8453  }
8454  catch(const Exception &e)
8455  {
8456  ErrorLog(32, e.Message);
8457  }
8458 }
8459 
8460 // ---------------------------------------------------------------------------
8461 void __fastcall TInterface::NewHomeButtonClick(TObject *Sender)
8462 {
8463  try
8464  {
8465  TrainController->LogEvent("NewHomeButtonClick");
8466  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NewHomeButtonClick");
8467  NewHomeButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
8468  if(!Display->ZoomOutFlag) // zoomed in mode
8469  {
8472  ResetChangedFileDataAndCaption(23, false); // false because no major changes made
8473  }
8474  else
8475  {
8478  }
8479  Utilities->CallLogPop(1188);
8480  NewHomeButton->Enabled = true; // restore, see above
8481  }
8482  catch(const Exception &e)
8483  {
8484  ErrorLog(174, e.Message);
8485  }
8486 }
8487 
8488 // ---------------------------------------------------------------------------
8489 void __fastcall TInterface::EditMenuClick(TObject *Sender)
8490  // added at v2.1.0 to allow CTRL+X, CTRL+C & CTRL+V in edit menu (see case BaseMode for more information)
8491 {
8492  try
8493  {
8494  CopyMenuItem->ShortCut = TextToShortCut("Ctrl+C");
8495  CutMenuItem->ShortCut = TextToShortCut("Ctrl+X");
8496  PasteMenuItem->ShortCut = TextToShortCut("Ctrl+V");
8497  }
8498  catch(const Exception &e)
8499  {
8500  ErrorLog(196, e.Message);
8501  }
8502 }
8503 
8504 // ---------------------------------------------------------------------------
8505 void __fastcall TInterface::SelectMenuItemClick(TObject *Sender)
8506 {
8507 // draw a rectangle with the left mouse button, enclosing whole 16 x 16 squares
8508  try
8509  {
8510  TrainController->LogEvent("SelectMenuItemClick");
8511  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectMenuItemClick");
8512  if(Level1Mode == TrackMode)
8513  {
8514  SelectionValid = false;
8516  SetLevel2TrackMode(34);
8517  }
8518  else if(Level1Mode == PrefDirMode)
8519  {
8522  }
8523  Utilities->CallLogPop(1189);
8524  }
8525  catch(const Exception &e)
8526  {
8527  ErrorLog(145, e.Message);
8528  }
8529 }
8530 
8531 // ---------------------------------------------------------------------------
8532 void __fastcall TInterface::ReselectMenuItemClick(TObject *Sender)
8533 {
8534  try
8535  {
8536  TrainController->LogEvent("ReselectMenuItemClick");
8537  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ReselectMenuItemClick");
8538  if((SelectBitmap->Height == 0) || (SelectBitmap->Width == 0))
8539  {
8540  Utilities->CallLogPop(1424);
8541  return;
8542  }
8543 
8544  int TLHCH = SelectBitmapHLoc;
8545  int TLHCV = SelectBitmapVLoc;
8546  int BRHCH = TLHCH + (SelectBitmap->Width / 16);
8547  int BRHCV = TLHCV + (SelectBitmap->Height / 16);
8548  TRect NewSelectRect(TLHCH, TLHCV, BRHCH, BRHCV);
8549  SelectRect = NewSelectRect;
8551  // set bitmap to reselected area (may be different if flip or mirror had been selected earlier)
8552  TRect Dest(0, 0, SelectBitmap->Width, SelectBitmap->Height);
8553  TRect Source(((SelectRect.left - Display->DisplayOffsetH) * 16), ((SelectRect.top - Display->DisplayOffsetV) * 16),
8554  ((SelectRect.right - Display->DisplayOffsetH) * 16), ((SelectRect.bottom - Display->DisplayOffsetV) * 16));
8555  SelectBitmap->Canvas->CopyRect(Dest, MainScreen->Canvas, Source);
8556 
8557  SelectionValid = true;
8558  ReselectMenuItem->Enabled = false;
8559  CutMenuItem->Enabled = true;
8560  CopyMenuItem->Enabled = true;
8561  FlipMenuItem->Enabled = true;
8562  MirrorMenuItem->Enabled = true;
8563  RotRightMenuItem->Enabled = true;
8564  RotLeftMenuItem->Enabled = true;
8565  RotateMenuItem->Enabled = true;
8566  PasteMenuItem->Enabled = false;
8567  DeleteMenuItem->Enabled = true;
8568  if(Track->IsTrackFinished())
8569  SelectLengthsMenuItem->Enabled = true; // only permit if finished because reverts to DistanceStart
8570  else
8571  SelectLengthsMenuItem->Enabled = false; // and that can only be used if track linked
8572  SelectBiDirPrefDirsMenuItem->Visible = false;
8573  CancelSelectionMenuItem->Enabled = true;
8574  mbLeftDown = false;
8575  // Level1Mode = TrackMode;
8576  // SetLevel1Mode(68);
8578  SetLevel2TrackMode(47);
8579  Utilities->CallLogPop(1425);
8580  }
8581  catch(const Exception &e)
8582  {
8583  ErrorLog(146, e.Message);
8584  }
8585 }
8586 
8587 // ---------------------------------------------------------------------------
8588 void __fastcall TInterface::CutMenuItemClick(TObject *Sender)
8589 {
8590  try
8591  {
8592  TrainController->LogEvent("CutMenuItemClick");
8593  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CutMenuItemClick");
8594  // Level1Mode = TrackMode;
8595  // SetLevel1Mode(69);
8597  SetLevel2TrackMode(35);
8598  Utilities->CallLogPop(1190);
8599  }
8600  catch(const Exception &e)
8601  {
8602  ErrorLog(147, e.Message);
8603  }
8604 }
8605 // ---------------------------------------------------------------------------
8606 
8607 void __fastcall TInterface::CopyMenuItemClick(TObject *Sender)
8608 {
8609  try
8610  {
8611  TrainController->LogEvent("CopyMenuItemClick");
8612  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CopyMenuItemClick");
8613  // Level1Mode = TrackMode;
8614  // SetLevel1Mode(70);
8616  SetLevel2TrackMode(36);
8617  Utilities->CallLogPop(1191);
8618  }
8619  catch(const Exception &e)
8620  {
8621  ErrorLog(148, e.Message);
8622  }
8623 }
8624 
8625 // ---------------------------------------------------------------------------
8626 void __fastcall TInterface::FlipMenuItemClick(TObject *Sender)
8627 {
8628  try
8629  {
8630  TrainController->LogEvent("FlipMenuItemClick");
8631  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FlipMenuItemClick");
8632  // reset values in SelectVector
8633  int VerSum = SelectRect.top + SelectRect.bottom - 1;
8634  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
8635  {
8636  // Note: (changed again in v2.4.0 to keep attributes) need to change flip, mirror & 180deg functions as only change speedtag without changing anything else.
8637  // This didn't matter before new paste with attributes added at v2.2.0 as a new element was built from the speedtag,
8638  // but now if do a reselect then cut and paste with attributes the wrong graphic is pasted and all other attributes
8639  // are wrong. Need to rebuild a new TrackElement from the new speedtag and use that in the select vector.
8640  // Note that if use Flip, mirror etc then all attributes lost anyway so ok to build a basic element.
8641  int VLoc = VerSum - Track->SelectVectorAt(8, x).VLoc;
8642  int HLoc = Track->SelectVectorAt(7, x).HLoc;
8644  TE.VLoc = VLoc;
8645  TE.HLoc = HLoc;
8646 
8647  TE.ActiveTrackElementName = Track->SelectVectorAt(37, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
8649  TE.Length01 = Track->SelectVectorAt(39, x).Length01;
8650  TE.Length23 = Track->SelectVectorAt(40, x).Length23;
8653  TE.SigAspect = Track->SelectVectorAt(43, x).SigAspect;
8654  Track->SelectVectorAt(26, x) = TE;
8655  }
8656  // reset values in SelectTextVector
8657  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(0); x++)
8658  {
8660  // also subtract font height, brings position approximately right
8661  TextItem->VPos = ((VerSum * 16) + 15) - TextItem->VPos - abs(TextItem->Font->Height);
8662  }
8663  // reset values in SelectGraphicVector so the midpoint of the graphic flips about the midline of the selection
8664  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
8665  {
8666  int MidVPosBeforeFlip = Track->SelectGraphicVector.at(x).VPos + (Track->SelectGraphicVector.at(x).Height) / 2;
8667  int MidVPosAfterFlip = ((VerSum * 16) + 15) - MidVPosBeforeFlip;
8668  int TopPosAfterFlip = MidVPosAfterFlip - (Track->SelectGraphicVector.at(x).Height) / 2;
8669  Track->SelectGraphicVector.at(x).VPos = TopPosAfterFlip;
8670  }
8672  SetLevel2TrackMode(48);
8673  Utilities->CallLogPop(1426);
8674  }
8675  catch(const Exception &e)
8676  {
8677  ErrorLog(149, e.Message);
8678  }
8679 }
8680 
8681 // ---------------------------------------------------------------------------
8682 void __fastcall TInterface::MirrorMenuItemClick(TObject *Sender)
8683 {
8684  try
8685  {
8686  TrainController->LogEvent("MirrorMenuItemClick");
8687  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MirrorMenuItemClick");
8688  // reset values in SelectVector
8689  int HorSum = SelectRect.left + SelectRect.right - 1;
8690  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
8691  {
8692  // See note above for FlipMenuItem relating to mods for v2.2.0
8693  int VLoc = Track->SelectVectorAt(22, x).VLoc;
8694  int HLoc = HorSum - Track->SelectVectorAt(6, x).HLoc;
8696  TE.VLoc = VLoc;
8697  TE.HLoc = HLoc;
8698 
8699  TE.ActiveTrackElementName = Track->SelectVectorAt(44, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
8701  TE.Length01 = Track->SelectVectorAt(46, x).Length01;
8702  TE.Length23 = Track->SelectVectorAt(47, x).Length23;
8705  TE.SigAspect = Track->SelectVectorAt(50, x).SigAspect;
8706 
8707 // if(Track->SelectVectorAt(28, x).TrackType == SignalPost) TE.SigAspect = Track->SelectVectorAt(29, x).SigAspect;//TrackType will be the same
8708  Track->SelectVectorAt(30, x) = TE;
8709 // Track->SelectVectorAt(, x).HLoc = HorSum - Track->SelectVectorAt(, x).HLoc;
8710 // Track->SelectVectorAt(, x).SpeedTag = Track->MirrorArray[Track->SelectVectorAt(, x).SpeedTag];
8711  }
8712  // reset values in SelectTextVector
8713  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(1); x++)
8714  {
8716  // also subtract half font height for each letter of text, brings position approximately right
8717  TextItem->HPos = ((HorSum * 16) + 15) - TextItem->HPos - (TextItem->TextString.Length() * 0.5 * abs(TextItem->Font->Height));
8718  }
8719  // reset values in SelectGraphicVector so the midpoint of the graphic mirrors about the midline of the selection
8720  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
8721  {
8722  int MidHPosBeforeMirror = Track->SelectGraphicVector.at(x).HPos + (Track->SelectGraphicVector.at(x).Width) / 2;
8723  int MidHPosAfterMirror = ((HorSum * 16) + 15) - MidHPosBeforeMirror;
8724  int LeftPosAfterMirror = MidHPosAfterMirror - (Track->SelectGraphicVector.at(x).Width) / 2;
8725  if(LeftPosAfterMirror < (SelectRect.left * 16)) // shouldn't go below left but check
8726  {
8727  LeftPosAfterMirror = SelectRect.left * 16;
8728  }
8729  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterMirror;
8730  }
8732  SetLevel2TrackMode(49);
8733  Utilities->CallLogPop(1427);
8734  }
8735  catch(const Exception &e)
8736  {
8737  ErrorLog(150, e.Message);
8738  }
8739 }
8740 
8741 // ---------------------------------------------------------------------------
8742 void __fastcall TInterface::RotateMenuItemClick(TObject *Sender)
8743 {
8744  try
8745  {
8746  TrainController->LogEvent("Rotate180MenuItemClick");
8747  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",Rotate180MenuItemClick");
8748  // reset values in SelectVector
8749  int HorSum = SelectRect.left + SelectRect.right - 1;
8750  int VerSum = SelectRect.top + SelectRect.bottom - 1;
8751  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
8752  {
8753  // See note above for FlipMenuItem relating to mods for v2.2.0
8754  int VLoc = VerSum - Track->SelectVectorAt(23, x).VLoc;
8755  int HLoc = HorSum - Track->SelectVectorAt(36, x).HLoc;
8757  TE.VLoc = VLoc;
8758  TE.HLoc = HLoc;
8759 
8760  TE.ActiveTrackElementName = Track->SelectVectorAt(51, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
8762  TE.Length01 = Track->SelectVectorAt(53, x).Length01;
8763  TE.Length23 = Track->SelectVectorAt(54, x).Length23;
8766  TE.SigAspect = Track->SelectVectorAt(57, x).SigAspect;
8767 
8768 // if(Track->SelectVectorAt(32, x).TrackType == SignalPost) TE.SigAspect = Track->SelectVectorAt(33, x).SigAspect; dropped in v2.4.0 for above
8769  Track->SelectVectorAt(34, x) = TE;
8770 // TTrackElement &TempEl = Track->SelectVectorAt(13, x);
8771 // TempEl.HLoc = HorSum - TempEl.HLoc;
8772 // TempEl.VLoc = VerSum - TempEl.VLoc;
8773 // TempEl.SpeedTag = Track->MirrorArray[Track->FlipArray[TempEl.SpeedTag]];
8774  }
8775  // reset values in SelectTextVector
8776  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(2); x++)
8777  {
8779  // also subtract half font height for each letter of text, brings position approximately right horizontally
8780  TextItem->HPos = ((HorSum * 16) + 15) - TextItem->HPos - (TextItem->TextString.Length() * 0.5 * abs(TextItem->Font->Height));
8781  // also subtract font height, brings position approximately right vertically
8782  TextItem->VPos = ((VerSum * 16) + 15) - TextItem->VPos - abs(TextItem->Font->Height);
8783  }
8784  // reset flip values in SelectGraphicVector so the midpoint of the graphic flips about the midline of the selection
8785  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
8786  {
8787  int MidVPosBeforeFlip = Track->SelectGraphicVector.at(x).VPos + (Track->SelectGraphicVector.at(x).Height) / 2;
8788  int MidVPosAfterFlip = ((VerSum * 16) + 15) - MidVPosBeforeFlip;
8789  int TopPosAfterFlip = MidVPosAfterFlip - (Track->SelectGraphicVector.at(x).Height) / 2;
8790  if(TopPosAfterFlip < (SelectRect.top * 16)) // shouldn't go above top but check
8791  {
8792  TopPosAfterFlip = SelectRect.top * 16;
8793  }
8794  Track->SelectGraphicVector.at(x).VPos = TopPosAfterFlip;
8795  }
8796  // reset mirror in SelectGraphicVector so the midpoint of the graphic mirrors about the midline of the selection
8797  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
8798  {
8799  int MidHPosBeforeMirror = Track->SelectGraphicVector.at(x).HPos + (Track->SelectGraphicVector.at(x).Width) / 2;
8800  int MidHPosAfterMirror = ((HorSum * 16) + 15) - MidHPosBeforeMirror;
8801  int LeftPosAfterMirror = MidHPosAfterMirror - (Track->SelectGraphicVector.at(x).Width) / 2;
8802  if(LeftPosAfterMirror < (SelectRect.left * 16)) // shouldn't go below left but check
8803  {
8804  LeftPosAfterMirror = SelectRect.left * 16;
8805  }
8806  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterMirror;
8807  }
8808  // Level1Mode = TrackMode;
8809  // SetLevel1Mode(73);
8811  SetLevel2TrackMode(50);
8812  Utilities->CallLogPop(1435);
8813  }
8814  catch(const Exception &e)
8815  {
8816  ErrorLog(151, e.Message);
8817  }
8818 }
8819 // ---------------------------------------------------------------------------
8820 
8821 void __fastcall TInterface::RotRightMenuItemClick(TObject *Sender)
8822 {
8823  try
8824  {
8825  TrainController->LogEvent("RotateRight90MenuItemClick");
8826  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RotateRight90MenuItemClick");
8827  Screen->Cursor = TCursor(-11); // Hourglass
8828  // check first if a square and if not give message & quit
8829  if((SelectRect.right - SelectRect.left) != (SelectRect.bottom - SelectRect.top))
8830  {
8831  // use left vertical side to make square & keep top lh corner unless rhs would exceed display, in which case use the right vertical & keep to rh corner
8832  int VertSize = SelectRect.bottom - SelectRect.top;
8833  if((SelectRect.Left + VertSize - Display->DisplayOffsetH) > Utilities->ScreenElementWidth)
8834  {
8835  // use right hand vertical & make square to left of that
8836  SelectRect.left = SelectRect.right - VertSize;
8837  }
8838  else
8839  {
8840  SelectRect.right = SelectRect.left + VertSize;
8841  }
8844  int button = Application->MessageBox
8845  (L"Original selection adjusted to make it square. 'OK' to keep this selection or 'Cancel' to make a new selection",
8846  L"Left click and hold here to move this message box", MB_OKCANCEL);
8847  if(button == IDCANCEL)
8848  {
8849  ResetSelectRect();
8850  Level1Mode = TrackMode; // call this first to clear everything, then set PrefDir mode
8851  SetLevel1Mode(133);
8853  SetLevel2TrackMode(59);
8855  Screen->Cursor = TCursor(-2); // Arrow
8856  Utilities->CallLogPop(2121);
8857  return;
8858  }
8859  }
8860  // set SelectBitmap (only need the dimensions here as not moving the selection)
8863  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
8864  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
8865  // store track elements and text in select vectors
8867  TTrackElement TempElement; // default element
8868  bool FoundFlag;
8869  for(int x = SelectRect.left; x < SelectRect.right; x++)
8870  {
8871  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
8872  {
8873  int ATVecPos = Track->GetVectorPositionFromTrackMap(57, x, y, FoundFlag);
8874  if(FoundFlag)
8875  {
8876  TempElement = Track->TrackElementAt(959, ATVecPos);
8877  if(TempElement.SpeedTag > 0)
8878  Track->SelectPush(TempElement);
8879  }
8880  }
8881  }
8882  // now store inactive elements
8883  for(int x = SelectRect.left; x < SelectRect.right; x++)
8884  {
8885  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
8886  {
8887  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(28, x, y, FoundFlag);
8888  if(FoundFlag)
8889  {
8890  TempElement = Track->InactiveTrackElementAt(126, IATVecPair.first);
8891  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
8892  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
8893  {
8894  TempElement = Track->InactiveTrackElementAt(127, IATVecPair.second);
8895  Track->SelectPush(TempElement);
8896  }
8897  }
8898  }
8899  }
8900  // store text items
8901  int LowSelectHPos = SelectRect.left * 16;
8902  int HighSelectHPos = SelectRect.right * 16;
8903  int LowSelectVPos = SelectRect.top * 16;
8904  int HighSelectVPos = SelectRect.bottom * 16;
8905  TextHandler->SelectTextVector.clear();
8906  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
8907  {
8908  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
8909  {
8910  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos < HighSelectVPos))
8911  {
8912  // have to create a new TextItem in order to create a new Font object
8913  // BUT: only create new items where they don't appear as named location names
8914  // in SelectVector, since those names shouldn't be copied or pasted.
8915  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
8916  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
8917  bool SelectVectorNamedElement = false;
8918  AnsiString SelectTextString; // new at v2.2.0
8919  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
8920  {
8921  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
8922  {
8923  SelectVectorNamedElement = true;
8924  break;
8925  }
8926  }
8927  if(SelectVectorNamedElement) // changed at v2.2.0
8928  {
8929  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
8930  }
8931  else // new at v2.2.0
8932  {
8933  SelectTextString = TextPtr->TextString;
8934  }
8935  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
8936  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
8937  }
8938  }
8939  }
8940  // store graphic items, but first clear SelectGraphicVector
8941  Track->SelectGraphicVector.clear();
8942  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
8943  {
8944  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
8945  UserGraphicPtr++)
8946  {
8947  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) && (UserGraphicPtr->VPos >=
8948  LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
8949  {
8950  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
8951  }
8952  }
8953  }
8954  // now transform the H & V for rh rotate
8955  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
8956  {
8957  int HLoc = SelectRect.bottom - 1 + SelectRect.left - Track->SelectVectorAt(74, x).VLoc;
8958  int VLoc = SelectRect.top - SelectRect.left + Track->SelectVectorAt(75, x).HLoc;
8960  TE.VLoc = VLoc;
8961  TE.HLoc = HLoc;
8962 
8963  TE.ActiveTrackElementName = Track->SelectVectorAt(58, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
8965  TE.Length01 = Track->SelectVectorAt(60, x).Length01;
8966  TE.Length23 = Track->SelectVectorAt(61, x).Length23;
8969  TE.SigAspect = Track->SelectVectorAt(64, x).SigAspect;
8970  Track->SelectVectorAt(65, x) = TE;
8971  }
8972  // reset values in SelectTextVector
8973  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(3); x++)
8974  {
8975 // no point trying to locate text properly as it stays horizontal so will always be wrongly placed, just list all itels vertically at lhs
8976 // & if a lot then some will extend beyond the selection
8978  // also subtract half font height for each letter of text, brings position approximately right horizontally
8979  TextItem->HPos = (SelectRect.left) * 16;
8980  TextItem->VPos = (SelectRect.top + x) * 16;
8981  }
8982  // reset values in SelectGraphicVector
8983  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
8984  {
8985  int MidHPosBeforeRotate = Track->SelectGraphicVector.at(x).HPos + Track->SelectGraphicVector.at(x).Width / 2;
8986  int MidVPosBeforeRotate = Track->SelectGraphicVector.at(x).VPos + Track->SelectGraphicVector.at(x).Height / 2;
8987  int MidHPosAfterRotate = ((SelectRect.bottom * 16) - 1) + (SelectRect.left * 16) - MidVPosBeforeRotate;
8988  int MidVPosAfterRotate = ((SelectRect.top - SelectRect.left) * 16) + MidHPosBeforeRotate;
8989  int LeftPosAfterRotate = MidHPosAfterRotate - (Track->SelectGraphicVector.at(x).Width) / 2;
8990  int TopPosAfterRotate = MidVPosAfterRotate - (Track->SelectGraphicVector.at(x).Height) / 2;
8991  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterRotate;
8992  Track->SelectGraphicVector.at(x).VPos = TopPosAfterRotate;
8993  }
8994  Screen->Cursor = TCursor(-2); // Arrow
8996  SetLevel2TrackMode(60);
8997  Utilities->CallLogPop(2122);
8998  }
8999  catch(const Exception &e)
9000  {
9001  ErrorLog(205, e.Message);
9002  }
9003 }
9004 
9005 // ---------------------------------------------------------------------------
9006 
9007 void __fastcall TInterface::RotLeftMenuItemClick(TObject *Sender)
9008 {
9009  try
9010  {
9011  TrainController->LogEvent("RotateLeft90MenuItemClick");
9012  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RotateLeft90MenuItemClick");
9013  Screen->Cursor = TCursor(-11); // Hourglass;
9014  // check first if a square and if not give message & quit
9015  if((SelectRect.right - SelectRect.left) != (SelectRect.bottom - SelectRect.top))
9016  {
9017  // use left vertical side to make square & keep top lh corner unless rhs would exceed display, in which case use the right vertical & keep to rh corner
9018  int VertSize = SelectRect.bottom - SelectRect.top;
9019  if((SelectRect.Left + VertSize - Display->DisplayOffsetH) > Utilities->ScreenElementWidth)
9020  {
9021  // use right hand vertical & make square to left of that
9022  SelectRect.left = SelectRect.right - VertSize;
9023  }
9024  else
9025  {
9026  SelectRect.right = SelectRect.left + VertSize;
9027  }
9030  int button = Application->MessageBox
9031  (L"Original selection adjusted to make it square. 'OK' to keep this selection or 'Cancel' to make a new selection",
9032  L"Left click and hold here to move this message box", MB_OKCANCEL);
9033  if(button == IDCANCEL)
9034  {
9035  ResetSelectRect();
9036  Level1Mode = TrackMode; // call this first to clear everything, then set PrefDir mode
9037  SetLevel1Mode(134);
9039  SetLevel2TrackMode(61);
9041  Screen->Cursor = TCursor(-2); // Arrow
9042  Utilities->CallLogPop(2123);
9043  return;
9044  }
9045  }
9046  // set SelectBitmap (only need the dimensions here as not moving the selection)
9049  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
9050  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
9051  // store track elements and text in select vectors
9053  TTrackElement TempElement; // default element
9054  bool FoundFlag;
9055  for(int x = SelectRect.left; x < SelectRect.right; x++)
9056  {
9057  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
9058  {
9059  int ATVecPos = Track->GetVectorPositionFromTrackMap(58, x, y, FoundFlag);
9060  if(FoundFlag)
9061  {
9062  TempElement = Track->TrackElementAt(960, ATVecPos);
9063  if(TempElement.SpeedTag > 0)
9064  Track->SelectPush(TempElement);
9065  }
9066  }
9067  }
9068  // now store inactive elements
9069  for(int x = SelectRect.left; x < SelectRect.right; x++)
9070  {
9071  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
9072  {
9073  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(29, x, y, FoundFlag);
9074  if(FoundFlag)
9075  {
9076  TempElement = Track->InactiveTrackElementAt(128, IATVecPair.first);
9077  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
9078  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
9079  {
9080  TempElement = Track->InactiveTrackElementAt(129, IATVecPair.second);
9081  Track->SelectPush(TempElement);
9082  }
9083  }
9084  }
9085  }
9086  // store text items
9087  int LowSelectHPos = SelectRect.left * 16;
9088  int HighSelectHPos = SelectRect.right * 16;
9089  int LowSelectVPos = SelectRect.top * 16;
9090  int HighSelectVPos = SelectRect.bottom * 16;
9091  TextHandler->SelectTextVector.clear();
9092  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
9093  {
9094  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
9095  {
9096  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos < HighSelectVPos))
9097  {
9098  // have to create a new TextItem in order to create a new Font object
9099  // BUT: only create new items where they don't appear as named location names
9100  // in SelectVector, since those names shouldn't be copied or pasted.
9101  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
9102  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
9103  bool SelectVectorNamedElement = false;
9104  AnsiString SelectTextString; // new at v2.2.0
9105  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
9106  {
9107  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
9108  {
9109  SelectVectorNamedElement = true;
9110  break;
9111  }
9112  }
9113  if(SelectVectorNamedElement) // changed at v2.2.0
9114  {
9115  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
9116  }
9117  else // new at v2.2.0
9118  {
9119  SelectTextString = TextPtr->TextString;
9120  }
9121  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
9122  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
9123  }
9124  }
9125  }
9126  // store graphic items, but first clear SelectGraphicVector
9127  Track->SelectGraphicVector.clear();
9128  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
9129  {
9130  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
9131  UserGraphicPtr++)
9132  {
9133  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) && (UserGraphicPtr->VPos >=
9134  LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
9135  {
9136  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
9137  }
9138  }
9139  }
9140  // now transform the H & V for lh rotate
9141  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9142  {
9143  int HLoc = SelectRect.left - SelectRect.top + Track->SelectVectorAt(76, x).VLoc;
9144  int VLoc = SelectRect.bottom - 1 + SelectRect.left - Track->SelectVectorAt(77, x).HLoc;
9146  TE.VLoc = VLoc;
9147  TE.HLoc = HLoc;
9148 
9149  TE.ActiveTrackElementName = Track->SelectVectorAt(66, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9151  TE.Length01 = Track->SelectVectorAt(68, x).Length01;
9152  TE.Length23 = Track->SelectVectorAt(69, x).Length23;
9155  TE.SigAspect = Track->SelectVectorAt(72, x).SigAspect;
9156  Track->SelectVectorAt(73, x) = TE;
9157  }
9158  // reset values in SelectTextVector
9159  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(4); x++)
9160  {
9161 // no point trying to locate text properly as it stays horizontal so will always be wrongly placed, just list all itels vertically at lhs
9162 // & if a lot then some will extend beyond the selection
9164  // also subtract half font height for each letter of text, brings position approximately right horizontally
9165  TextItem->HPos = (SelectRect.left) * 16;
9166  TextItem->VPos = (SelectRect.top + x) * 16;
9167  }
9168  // reset values in SelectGraphicVector
9169  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9170  {
9171  int MidHPosBeforeRotate = Track->SelectGraphicVector.at(x).HPos + Track->SelectGraphicVector.at(x).Width / 2;
9172  int MidVPosBeforeRotate = Track->SelectGraphicVector.at(x).VPos + Track->SelectGraphicVector.at(x).Height / 2;
9173  int MidHPosAfterRotate = ((SelectRect.left - SelectRect.top) * 16) + MidVPosBeforeRotate;
9174  int MidVPosAfterRotate = ((SelectRect.bottom * 16) - 1) + (SelectRect.left * 16) - MidHPosBeforeRotate;
9175  int LeftPosAfterRotate = MidHPosAfterRotate - (Track->SelectGraphicVector.at(x).Width) / 2;
9176  int TopPosAfterRotate = MidVPosAfterRotate - (Track->SelectGraphicVector.at(x).Height) / 2;
9177  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterRotate;
9178  Track->SelectGraphicVector.at(x).VPos = TopPosAfterRotate;
9179  }
9180  Screen->Cursor = TCursor(-2); // Arrow
9182  SetLevel2TrackMode(62);
9183  Utilities->CallLogPop(2124);
9184  }
9185  catch(const Exception &e)
9186  {
9187  ErrorLog(206, e.Message);
9188  }
9189 }
9190 
9191 // ---------------------------------------------------------------------------
9192 
9193 void __fastcall TInterface::PasteMenuItemClick(TObject *Sender)
9194 {
9195  try
9196  {
9197  TrainController->LogEvent("PasteMenuItemClick");
9198  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PasteMenuItemClick");
9199  // Level1Mode = TrackMode;
9200  // SetLevel1Mode(74);
9202  SetLevel2TrackMode(58);
9203  Utilities->CallLogPop(2060);
9204  }
9205  catch(const Exception &e)
9206  {
9207  ErrorLog(198, e.Message);
9208  }
9209 }
9210 
9211 // ---------------------------------------------------------------------------
9212 void __fastcall TInterface::DeleteMenuItemClick(TObject *Sender)
9213 {
9214  try
9215  {
9216  TrainController->LogEvent("DeleteMenuItemClick");
9217  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteMenuItemClick");
9218  // Level1Mode = TrackMode;
9219  // SetLevel1Mode(75);
9221  SetLevel2TrackMode(38);
9222  Utilities->CallLogPop(1193);
9223  }
9224  catch(const Exception &e)
9225  {
9226  ErrorLog(153, e.Message);
9227  }
9228 }
9229 // ---------------------------------------------------------------------------
9230 
9231 void __fastcall TInterface::SelectLengthsMenuItemClick(TObject *Sender)
9232 {
9233  try
9234  {
9235  TrainController->LogEvent("SelectLengthsMenuItemClick");
9236  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectLengthsMenuItemClick");
9237  TrackElementPanel->Visible = false;
9238  TrackLengthPanel->Visible = true;
9239  TrackLengthPanel->SetFocus();
9240  SelectLengthsFlag = true;
9241  InfoPanel->Visible = true;
9242  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Set values or leave blank for no change";
9243  ShowMessage("Note: length value will apply to each element's track within the selection");
9244  DistanceBox->Text = "";
9245  SpeedLimitBox->Text = "";
9248  ResetChangedFileDataAndCaption(19, true); // true for NonPrefDirChangesMade
9249  Utilities->CallLogPop(1414);
9250  }
9251  catch(const Exception &e)
9252  {
9253  ErrorLog(154, e.Message);
9254  }
9255 }
9256 
9257 // ---------------------------------------------------------------------------
9258 
9259 void __fastcall TInterface::SelectBiDirPrefDirsMenuItemClick(TObject *Sender)
9260 {
9261 /* SelectVector contains all the track elements (and inactive elements but don't need them), so create up to 4 PrefDir
9262  elements from each one, and add each into ConstructPrefDir, then when all added use ConsolidatePrefDirs to add to EveryPrefDir
9263 */
9264  try
9265  {
9266  TrainController->LogEvent("SelectBiDirPrefDirsMenuItemClick");
9267  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectBiDirPrefDirsMenuItemClick");
9269  bool FoundFlag = false;
9270  if(Track->SelectVector.empty())
9271  {
9272  Utilities->CallLogPop(1550);
9273  return;
9274  }
9275  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9276  {
9277  TTrackElement TE = Track->SelectVectorAt(14, x);
9278  int VecPos = Track->GetVectorPositionFromTrackMap(42, TE.HLoc, TE.VLoc, FoundFlag);
9279  if(FoundFlag)
9280  {
9281  if((TE.TrackType == Points) || (TE.TrackType == Bridge) || (TE.TrackType == Crossover)) // 2-track element
9282  {
9283  TPrefDirElement PE0(TE, TE.Link[0], 0, TE.Link[1], 1, VecPos);
9285  TPrefDirElement PE1(TE, TE.Link[1], 1, TE.Link[0], 0, VecPos);
9287  TPrefDirElement PE2(TE, TE.Link[2], 2, TE.Link[3], 3, VecPos);
9289  TPrefDirElement PE3(TE, TE.Link[3], 3, TE.Link[2], 2, VecPos);
9291  }
9292  else if((TE.TrackType == Simple) || (TE.TrackType == Buffers) || (TE.TrackType == SignalPost) || (TE.TrackType == Continuation) ||
9293  (TE.TrackType == GapJump) || (TE.TrackType == FootCrossing))
9294  // need to list these explicitly since inactive elements will still be 'found' if there is an active element
9295  // at the same position
9296  {
9297  TPrefDirElement PE0(TE, TE.Link[0], 0, TE.Link[1], 1, VecPos);
9299  TPrefDirElement PE1(TE, TE.Link[1], 1, TE.Link[0], 0, VecPos);
9301  }
9302  }
9303  }
9305  ResetChangedFileDataAndCaption(22, false);
9306  // RlyFile = false; - don't alter this just for PrefDir changes
9307  Level1Mode = BaseMode; // call this first to clear everything, then set PrefDir mode
9308  SetLevel1Mode(30);
9310  SetLevel1Mode(31); // calls Clearand... to display all PrefDirs
9311  Utilities->CallLogPop(1549);
9312  }
9313  catch(const Exception &e)
9314  {
9315  ErrorLog(155, e.Message);
9316  }
9317 }
9318 
9319 // ---------------------------------------------------------------------------
9320 void __fastcall TInterface::CancelSelectionMenuItemClick(TObject *Sender)
9321 {
9322  try
9323  {
9324  TrainController->LogEvent("CancelSelectionClick");
9325  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CancelSelectionClick");
9326  ClearandRebuildRailway(46); // to remove the selection outline
9327  SelectionValid = false;
9328  Track->CopyFlag = false;
9330  ResetSelectRect();
9331  if(Level1Mode == TrackMode)
9332  {
9333  SetLevel1Mode(76);
9335  SetLevel2TrackMode(39);
9336  }
9337  else if(Level1Mode == PrefDirMode)
9338  {
9339  SetLevel1Mode(32);
9340  }
9341  Utilities->CallLogPop(1413);
9342  }
9343  catch(const Exception &e)
9344  {
9345  ErrorLog(156, e.Message);
9346  }
9347 }
9348 
9349 // ---------------------------------------------------------------------------
9350 void __fastcall TInterface::LoadTimetableMenuItemClick(TObject *Sender)
9351 {
9352  try
9353  {
9354  TrainController->LogEvent("LoadTimetableMenuItemClick");
9355  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LoadTimetableMenuItemClick");
9356  TimetableDialog->Filter = "Timetable file (*.ttb)|*.ttb";
9357  // reset all message flags, stops them being given twice new at v2.4.0
9358  TrainController->SSHigh = false;
9359  TrainController->MRSHigh = false;
9360  TrainController->MRSLow = false;
9361  TrainController->MassHigh = false;
9362  TrainController->BFHigh = false;
9363  TrainController->BFLow = false;
9364  TrainController->PwrHigh = false;
9365  TrainController->SigSHigh = false;
9366  TrainController->SigSLow = false;
9367  if(TimetableDialog->Execute())
9368  {
9369  TrainController->LogEvent("LoadTimetable " + TimetableDialog->FileName);
9370  bool CheckLocationsExistInRailwayTrue = true;
9371  if(TrainController->TimetableIntegrityCheck(0, AnsiString(TimetableDialog->FileName).c_str(), true, CheckLocationsExistInRailwayTrue))
9372  // true for GiveMessages
9373  {
9374  Screen->Cursor = TCursor(-11); // Hourglass;
9375  std::ifstream TTBLFile(AnsiString(TimetableDialog->FileName).c_str(), std::ios_base::binary);
9376  if(TTBLFile.is_open())
9377  {
9378  bool SessionFileFalse = false;
9379  if(BuildTrainDataVectorForLoadFile(0, TTBLFile, true, CheckLocationsExistInRailwayTrue, SessionFileFalse)) // true for GiveMessages
9380  {
9381  SaveTempTimetableFile(0, TimetableDialog->FileName);
9382  } // don't need an 'else' as messages given in BuildTrainDataVectorForLoadFile
9383  }
9384  else
9385  {
9386  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
9387  }
9388  Screen->Cursor = TCursor(-2); // Arrow
9389  } // if(TimetableIntegrityCheck
9390  else
9391  ShowMessage("Timetable preliminary integrity check failed - unable to load");
9392  } // if(TimetableDialog->Execute())
9393  // else ShowMessage("Load Aborted");
9394  Utilities->CallLogPop(752);
9395  }
9396  catch(const Exception &e)
9397  {
9398  ErrorLog(34, e.Message);
9399  }
9400 }
9401 
9402 // ---------------------------------------------------------------------------
9403 void __fastcall TInterface::TakeSignallerControlMenuItemClick(TObject *Sender)
9404 {
9405  try
9406  {
9407  TrainController->LogEvent("SignallerControl1Click");
9408  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SignallerControl1Click");
9410  Train.SignallerStoppingFlag = false;
9411  Train.TrainMode = Signaller;
9412  if(Train.MaxRunningSpeed > Train.SignallerMaxSpeed)
9413  {
9414  Train.MaxRunningSpeed = Train.SignallerMaxSpeed;
9415  }
9416  if(Train.Stopped())
9417  Train.SignallerStopped = true; // condition added at v2.4.0 to allow for taking sig control of failed moving trains
9418  Train.CallingOnFlag = false; // in case was set, wouldn't start anyway if called on as SignallerStopped = true
9420  Train.PlotTrain(5, Display);
9421  AnsiString LocName = "";
9422  if(Train.LeadElement > -1)
9423  {
9424  LocName = Track->TrackElementAt(633, Train.LeadElement).ActiveTrackElementName;
9425  }
9426  if((LocName == "") && (Train.MidElement > -1))
9427  {
9428  LocName = Track->TrackElementAt(634, Train.MidElement).ActiveTrackElementName;
9429  }
9430 
9431  // store the value that allow restoration of tt control or not - RestoreTimetableLocation
9432  if(Train.StoppedAtLocation && (LocName != ""))
9433  {
9434  Train.RestoreTimetableLocation = LocName;
9435  }
9436  else
9437  {
9438  Train.RestoreTimetableLocation = "";
9439  }
9440 
9441  // check whether need to offer 'pass red signal'
9442  if(!Train.StoppedAtSignal && Train.StoppedAtLocation)
9443  {
9444  int NextElementPosition = Track->TrackElementAt(775, Train.LeadElement).Conn[Train.LeadExitPos];
9445  int NextEntryPos = Track->TrackElementAt(776, Train.LeadElement).ConnLinkPos[Train.LeadExitPos];
9446  if((NextElementPosition > -1) && (NextEntryPos > -1))
9447  {
9448  if((Track->TrackElementAt(777, NextElementPosition).Config[Track->GetNonPointsOppositeLinkPos(NextEntryPos)] == Signal) &&
9449  (Track->TrackElementAt(778, NextElementPosition).Attribute == 0))
9450  { // set both StoppedAtLocation & StoppedAtSignal, so that 'pass red signal' is offered in popup menu rather than move
9451  // forwards, but don't change the background colour so still shows as stopped at location
9452  Train.StoppedAtSignal = true;
9453  }
9454  }
9455  }
9456  // find element ID if no locname
9457  if((LocName == "") && Train.LeadElement > -1)
9458  {
9459  LocName = Track->TrackElementAt(635, Train.LeadElement).ElementID;
9460  }
9461  if((LocName == "") && (Train.MidElement > -1))
9462  {
9463  LocName = Track->TrackElementAt(636, Train.MidElement).ElementID;
9464  }
9465  Train.LogAction(0, Train.HeadCode, "", TakeSignallerControl, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
9466  Utilities->CallLogPop(1772);
9467  }
9468  catch(const Exception &e)
9469  {
9470  ErrorLog(157, e.Message);
9471  }
9472 }
9473 
9474 // ---------------------------------------------------------------------------
9475 
9476 void __fastcall TInterface::TimetableControlMenuItemClick(TObject *Sender)
9477 {
9478  try
9479  {
9480  TrainController->LogEvent("TimetableControlMenuItemClick");
9481  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TimetableControlMenuItemClick");
9483  Train.SignallerStoppingFlag = false;
9484  Train.TrainMode = Timetable;
9485  Train.SignallerStopped = false;
9486  Train.StoppedAfterSPAD = false;
9487  Train.SPADFlag = false;
9490 // red headcode[0]
9491  Train.PlotTrain(6, Display);
9492  AnsiString LocName = "";
9493  if(Train.LeadElement > -1)
9494  {
9495  LocName = Track->TrackElementAt(645, Train.LeadElement).ActiveTrackElementName;
9496  }
9497  if((LocName == "") && (Train.MidElement > -1))
9498  {
9499  LocName = Track->TrackElementAt(647, Train.MidElement).ActiveTrackElementName;
9500  }
9501  if((LocName == "") && Train.LeadElement > -1)
9502  {
9503  LocName = Track->TrackElementAt(646, Train.LeadElement).ElementID;
9504  }
9505  if((LocName == "") && (Train.MidElement > -1))
9506  {
9507  LocName = Track->TrackElementAt(648, Train.MidElement).ElementID;
9508  }
9509  if((Train.ActionVectorEntryPtr->LocationType == AtLocation) && (LocName == Train.ActionVectorEntryPtr->LocationName))
9510  {
9511  Train.StoppedAtLocation = true;
9512  Train.LastActionTime = TrainController->TTClockTime; // by itself this only affects trains that have still to arrive, if waiting to
9513  // depart the departure time & TRS time have already been calculated so need to
9514  // force a recalculation - see below
9515  Train.DepartureTimeSet = false; // force it to be recalculated based on new LastActionTime (if waiting to arrive this is false anyway)
9516  if(!Train.TrainFailed)
9517  {
9519  }
9520  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9521  if((Train.ActionVectorEntryPtr->FormatType == TimeLoc) && (Train.ActionVectorEntryPtr->ArrivalTime >= TDateTime(0)))
9522  { // Timetable indicates that train still waiting to arrive for a TimeLoc arrival so send message and mark as arrived
9523  Train.LogAction(28, Train.HeadCode, "", Arrive, LocName, Train.ActionVectorEntryPtr->ArrivalTime, Train.ActionVectorEntryPtr->Warning);
9524  Train.ActionVectorEntryPtr++; // advance pointer past arrival //added at v1.2.0
9525  }
9526  else if((Train.ActionVectorEntryPtr->FormatType == TimeTimeLoc) && !(Train.TimeTimeLocArrived))
9527  { // Timetable indicates that train still waiting to arrive for a TimeTimeLoc arrival so send message and mark as arrived
9528  Train.LogAction(29, Train.HeadCode, "", Arrive, LocName, Train.ActionVectorEntryPtr->ArrivalTime, Train.ActionVectorEntryPtr->Warning);
9529  Train.TimeTimeLocArrived = true;
9530  // NB: No need for 'Train.ActionVectorEntryPtr++' because still to act on the departure time
9531  }
9532  }
9533  else
9534  {
9535  int NextElementPos = -1; // addition for v1.3.2 due to Carwyn Thomas error
9536  int NextEntryPos = -1; // ---ditto---
9537  if(Train.LeadElement > -1) // ---ditto---
9538  { // ---ditto---
9539  NextElementPos = Track->TrackElementAt(658, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
9540  NextEntryPos = Track->TrackElementAt(659, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
9541  } // ---ditto---
9542  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9543  if(!Train.TrainFailed)
9544  {
9545  Train.PlotTrainWithNewBackgroundColour(31, clNormalBackground, Display); // to remove other background if was present, moved from
9546  } // within Train.AbleToMove at v2.4.0 to cancel signal stop background
9547  if(Train.AbleToMove(1)) // if has no power
9548  {
9549  Train.EntrySpeed = 0; // moved from below for v1.3.2 after Carwyn Thomas error
9550  Train.EntryTime = TrainController->TTClockTime; // ---Ditto---
9551  Train.FirstHalfMove = true; // ---Ditto---
9552  if((NextElementPos > -1) && (NextEntryPos > -1)) // changed from if(NextElementPos >= 0) as above
9553  {
9554  // Train.EntrySpeed = 0;
9555  // Train.EntryTime = TrainController->TTClockTime;
9556  // Train.FirstHalfMove = true;
9557  Train.SetTrainMovementValues(15, NextElementPos, NextEntryPos);
9558  }
9559  // else follow the continuations //added these 3 conditions for v1.3.2 after Carwyn Thomas error
9560  else if((Train.LeadElement > -1) && (Track->TrackElementAt(894, Train.LeadElement).TrackType == Continuation))
9561  {
9562  Train.SetTrainMovementValues(21, Train.LeadElement, Train.LeadEntryPos); // Use LeadElement for calcs if lead is a continuation
9563  }
9564  else if((Train.MidElement > -1) && (Track->TrackElementAt(895, Train.MidElement).TrackType == Continuation))
9565  {
9566  Train.SetTrainMovementValues(22, Train.MidElement, Train.MidEntryPos); // Use MidElement for calcs if Mid is a continuation
9567  }
9568  else if((Train.LagElement > -1) && (Track->TrackElementAt(896, Train.LagElement).TrackType == Continuation))
9569  {
9570  Train.SetTrainMovementValues(23, Train.LagElement, Train.LagEntryPos); // Use LagElement for calcs if Lag is a continuation
9571  }
9572  }
9573  else if(Train.StoppedAtSignal)
9574  {
9575  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9576  if(!Train.TrainFailed)
9577  {
9579  }
9580  // TrainController->LogActionError(42, Train.HeadCode, "", SignalHold, Track->TrackElementAt(757, NextElementPos).ElementID);
9581  }
9582  }
9583  Train.LogAction(1, Train.HeadCode, "", RestoreTimetableControl, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
9584  Utilities->CallLogPop(1195);
9585  }
9586  catch(const Exception &e)
9587  {
9588  ErrorLog(158, e.Message);
9589  }
9590 }
9591 
9592 // ---------------------------------------------------------------------------
9593 
9594 void __fastcall TInterface::ChangeDirectionMenuItemClick(TObject *Sender)
9595 {
9596  try
9597  {
9598  TrainController->LogEvent("ChangeDirectionMenuItemClick");
9599  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ChangeDirectionMenuItemClick");
9601  Train.SignallerStoppingFlag = false;
9602  Train.SignallerChangeTrainDirection(0); // this unplots & replots train, which checks for facing signal and sets StoppedAtSignal if req'd
9603  Train.SignallerStopped = true;
9604  AnsiString LocName = "";
9605  if(Train.LeadElement > -1)
9606  {
9607  LocName = Track->TrackElementAt(637, Train.LeadElement).ActiveTrackElementName;
9608  }
9609  if((LocName == "") && (Train.MidElement > -1))
9610  {
9611  LocName = Track->TrackElementAt(638, Train.MidElement).ActiveTrackElementName;
9612  }
9613  if((LocName == "") && Train.LeadElement > -1)
9614  {
9615  LocName = Track->TrackElementAt(639, Train.LeadElement).ElementID;
9616  }
9617  if((LocName == "") && (Train.MidElement > -1))
9618  {
9619  LocName = Track->TrackElementAt(640, Train.MidElement).ElementID;
9620  }
9621  Train.LogAction(2, Train.HeadCode, "", SignallerChangeDirection, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
9622  Utilities->CallLogPop(1196);
9623  }
9624  catch(const Exception &e)
9625  {
9626  ErrorLog(159, e.Message);
9627  }
9628 }
9629 // ---------------------------------------------------------------------------
9630 
9631 void __fastcall TInterface::MoveForwardsMenuItemClick(TObject *Sender)
9632 {
9633  try
9634  {
9635  TrainController->LogEvent("MoveForwardsMenuItemClick");
9636  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveForwardsMenuItemClick");
9638  Train.SignallerStoppingFlag = false;
9639  if(!Train.AbleToMove(2))
9640  { // shouldn't be here as when unable to move MoveForwards shouldn't be enabled, but leave in as a precaution
9641  Utilities->CallLogPop(1197);
9642  return;
9643  }
9644  Train.SignallerStopped = false;
9645  Train.StoppedAfterSPAD = false; // in case had been set
9646  Train.SPADFlag = false;
9647  Train.StoppedAtLocation = false; // may not have been set but reset anyway
9648  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9650  Train.EntrySpeed = 0;
9652  Train.FirstHalfMove = true;
9653  int NextElementPos = -1; // addition for v1.3.2 due to Carwyn Thomas error
9654  int NextEntryPos = -1; // ---ditto---
9655  if(Train.LeadElement > -1) // ---ditto---
9656  { // ---ditto---
9657  NextElementPos = Track->TrackElementAt(652, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
9658  NextEntryPos = Track->TrackElementAt(657, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
9659  } // ---ditto---
9660  if((NextElementPos > -1) && (NextEntryPos > -1))
9661  {
9662  Train.SetTrainMovementValues(14, NextElementPos, NextEntryPos); // NextElement is the element to be entered
9663  }
9664  // else follow the continuations
9665  else if((Train.LeadElement > -1) && (Track->TrackElementAt(784, Train.LeadElement).TrackType == Continuation))
9666  {
9667  Train.SetTrainMovementValues(17, Train.LeadElement, Train.LeadEntryPos); // Use LeadElement for calcs if lead is a continuation
9668  }
9669  else if((Train.MidElement > -1) && (Track->TrackElementAt(785, Train.MidElement).TrackType == Continuation))
9670  {
9671  Train.SetTrainMovementValues(18, Train.MidElement, Train.MidEntryPos); // Use MidElement for calcs if Mid is a continuation
9672  }
9673  else if((Train.LagElement > -1) && (Track->TrackElementAt(786, Train.LagElement).TrackType == Continuation))
9674  {
9675  Train.SetTrainMovementValues(19, Train.LagElement, Train.LagEntryPos); // Use LagElement for calcs if Lag is a continuation
9676  }
9677  Train.LogAction(3, Train.HeadCode, "", SignallerMoveForwards, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
9678  Utilities->CallLogPop(1198);
9679  }
9680  catch(const Exception &e)
9681  {
9682  ErrorLog(160, e.Message);
9683  }
9684 }
9685 // ---------------------------------------------------------------------------
9686 
9687 void __fastcall TInterface::SignallerJoinedByMenuItemClick(TObject *Sender)
9688 { // new at v2.4.0
9689  try
9690  {
9691  TrainController->LogEvent("JoinedByMenuItemClick");
9692  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",JoinedByMenuItemClick");
9693  TTrain *TrainToBeJoinedBy;
9695  if(ThisTrain.IsThereAnAdjacentTrain(1, TrainToBeJoinedBy)) // this must come before both powers zero check in order to set a valid TrainToBeJoinedBy
9696  {
9697  if(TrainToBeJoinedBy->TrainMode != Signaller)
9698  {
9699  TrainController->StopTTClockMessage(91, "Adjacent train must be under signaller control in order to join");
9700  Utilities->CallLogPop(2156);
9701  return;
9702  }
9703  // here if there is an adjacent train under signaller control
9704  if((TrainToBeJoinedBy->PowerAtRail < 1) && (ThisTrain.PowerAtRail < 1))
9705  {
9706  ShowMessage("Can't join two trains when both are without power");
9707  Utilities->CallLogPop(2157);
9708  return;
9709  }
9710  AnsiString TrainToBeJoinedByHeadCode = TrainToBeJoinedBy->HeadCode;
9711  // set new values for mass etc
9712  double OtherBrakeForce = TrainToBeJoinedBy->MaxBrakeRate * TrainToBeJoinedBy->Mass;
9713  double OwnBrakeForce = ThisTrain.MaxBrakeRate * ThisTrain.Mass;
9714  double CombinedBrakeRate = (OtherBrakeForce + OwnBrakeForce) / (TrainToBeJoinedBy->Mass + ThisTrain.Mass);
9715  ThisTrain.Mass += TrainToBeJoinedBy->Mass;
9716  ThisTrain.MaxBrakeRate = CombinedBrakeRate;
9717  ThisTrain.PowerAtRail += TrainToBeJoinedBy->PowerAtRail;
9718  ThisTrain.AValue = sqrt(2 * ThisTrain.PowerAtRail / ThisTrain.Mass);
9719 
9720  TrainToBeJoinedBy->TrainGone = true; // this will cause other train to be deleted
9721  TrainToBeJoinedBy->JoinedOtherTrainFlag = true;
9722  AnsiString LocName = "";
9723  if(ThisTrain.LeadElement > -1)
9724  {
9725  LocName = Track->TrackElementAt(979, ThisTrain.LeadElement).ActiveTrackElementName;
9726  }
9727  if((LocName == "") && (ThisTrain.MidElement > -1))
9728  {
9729  LocName = Track->TrackElementAt(980, ThisTrain.MidElement).ActiveTrackElementName;
9730  }
9731  if((LocName == "") && ThisTrain.LeadElement > -1)
9732  {
9733  LocName = Track->TrackElementAt(981, ThisTrain.LeadElement).ElementID;
9734  }
9735  if((LocName == "") && (ThisTrain.MidElement > -1))
9736  {
9737  LocName = Track->TrackElementAt(982, ThisTrain.MidElement).ElementID;
9738  }
9739  ThisTrain.StoppedWithoutPower = true;
9740  if(ThisTrain.PowerAtRail >= 1)
9741  {
9742  ThisTrain.StoppedWithoutPower = false;
9743  }
9744  ThisTrain.TrainFailed = false; // if had failed then no longer failed, even if joining train has no power
9745  if(!ThisTrain.StoppedAtLocation)
9746  {
9747  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9749  }
9750  else
9751  {
9752  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9754  }
9755  ThisTrain.SignallerStopped = true; // maybe as well as stopped without power, thought that takes precedence in floating window
9756  ThisTrain.LogAction(34, ThisTrain.HeadCode, TrainToBeJoinedBy->HeadCode, SignallerJoin, LocName, TDateTime(0), false); // TDateTime isn't used
9757  ThisTrain.ZeroPowerNoFrontSplitMessage = false; // added at v2.4.0, no need to include TrainToBeJoinedBy as that will be removed
9758  ThisTrain.ZeroPowerNoRearSplitMessage = false;
9759  ThisTrain.FailedTrainNoFinishJoinMessage = false;
9760  ThisTrain.ZeroPowerNoJoinedByMessage = false;
9761  ThisTrain.ZeroPowerNoCDTMessage = false;
9762  ThisTrain.ZeroPowerNoNewServiceMessage = false;
9764  ThisTrain.ZeroPowerNoRepeatShuttleMessage = false;
9766  Utilities->CallLogPop(2158);
9767  }
9768  }
9769  catch(const Exception &e)
9770  {
9771  ErrorLog(207, e.Message);
9772  }
9773 }
9774 // ---------------------------------------------------------------------------
9775 
9776 void __fastcall TInterface::RepairFailedTrainMenuItemClick(TObject *Sender)
9777 { // added at v2.4.0
9778  try
9779  {
9780  TrainController->LogEvent("RepairFailedTrainMenuItemClick");
9781  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedTrainMenuItemClick");
9783  Train.TrainFailed = false;
9784  Train.StoppedWithoutPower = false;
9785  Train.SignallerStopped = true;
9786  if(!Train.StoppedAtLocation)
9787  {
9788  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9790  }
9791  else
9792  {
9793  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9795  }
9796  Train.PowerAtRail = Train.OriginalPowerAtRail; // recover from original value, new at v2.4.0
9797  Train.AValue = sqrt(2 * Train.PowerAtRail / Train.Mass);
9798  Train.SetTrainMovementValues(24, Train.LeadElement, Train.LeadEntryPos);
9799  AnsiString LocName = "";
9800  if(Train.LeadElement > -1)
9801  {
9802  LocName = Track->TrackElementAt(983, Train.LeadElement).ActiveTrackElementName;
9803  }
9804  if((LocName == "") && (Train.MidElement > -1))
9805  {
9806  LocName = Track->TrackElementAt(984, Train.MidElement).ActiveTrackElementName;
9807  }
9808  if((LocName == "") && Train.LeadElement > -1)
9809  {
9810  LocName = Track->TrackElementAt(985, Train.LeadElement).ElementID;
9811  }
9812  if((LocName == "") && (Train.MidElement > -1))
9813  {
9814  LocName = Track->TrackElementAt(986, Train.MidElement).ElementID;
9815  }
9816  Train.LogAction(35, Train.HeadCode, "", RepairFailedTrain, LocName, TrainController->TTClockTime, false); // false for no warning
9817  Train.ZeroPowerNoFrontSplitMessage = false;
9818  Train.ZeroPowerNoRearSplitMessage = false;
9819  Train.FailedTrainNoFinishJoinMessage = false;
9820  Train.ZeroPowerNoJoinedByMessage = false;
9821  Train.ZeroPowerNoCDTMessage = false;
9822  Train.ZeroPowerNoNewServiceMessage = false;
9824  Train.ZeroPowerNoRepeatShuttleMessage = false;
9826  Utilities->CallLogPop(2159);
9827  }
9828  catch(const Exception &e)
9829  {
9830  ErrorLog(208, e.Message);
9831  }
9832 }
9833 
9834 // ---------------------------------------------------------------------------
9835 
9836 void __fastcall TInterface::SignallerControlStopMenuItemClick(TObject *Sender)
9837 {
9838  try
9839  {
9840  TrainController->LogEvent("SignallerControlStopMenuItemClick");
9841  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SignallerControlStopMenuItemClick");
9844  if(Train.LeadElement > -1)
9845  {
9846  if(Track->TrackElementAt(787, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
9847  {
9848  Train.SignallerStoppingFlag = true;
9849  Train.SignallerStopBrakeRate = 0;
9850  Train.LogAction(24, Train.HeadCode, "", SignallerControlStop, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
9851  }
9852  else
9854  }
9855  else
9857  Utilities->CallLogPop(1553);
9858  }
9859  catch(const Exception &e)
9860  {
9861  ErrorLog(161, e.Message);
9862  }
9863 }
9864 
9865 // ---------------------------------------------------------------------------
9866 void __fastcall TInterface::PassRedSignalMenuItemClick(TObject *Sender)
9867 {
9868  try
9869  {
9870  TrainController->LogEvent("PassRedSignalMenuItemClick");
9871  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PassRedSignalMenuItemClick");
9873  Train.SignallerStoppingFlag = false;
9874  int NextElementPos = Track->TrackElementAt(712, Train.LeadElement).Conn[Train.LeadExitPos];
9875  if(NextElementPos < 0)
9876  {
9877  throw Exception("Error, no element in front in PassRedSignalMenuItemClick");
9878  }
9879  TTrackElement &TrackElement = Track->TrackElementAt(653, NextElementPos);
9880 /* drop this error as may be some circumstances where behind a signal in sig mode but not stopped at signal
9881  if(!Train.StoppedAtSignal)
9882  {
9883  throw Exception("Error, not StoppedAtSignal in PassRedSignalMenuItemClick");
9884  }
9885 */
9886  if(TrackElement.TrackType != SignalPost)
9887  {
9888  throw Exception("Error, next element not a signal type in PassRedSignalMenuItemClick");
9889  }
9890  Train.SignallerStopped = false;
9891  Train.StoppedAtLocation = false; // may have started at station in signaller mode and also at a red signal, in this case both SignallerStopped
9892  // and StoppedAtLocation are set but the background colour stays pale green for station, not signal,
9893  // since no need to alert the user
9894  Train.StoppedAfterSPAD = false; // in case had been set
9895  Train.SPADFlag = false;
9896  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9898  Train.AllowedToPassRedSignal = true;
9899  Train.LogAction(4, Train.HeadCode, "", SignallerPassRedSignal, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
9900  Utilities->CallLogPop(1199);
9901  }
9902  catch(const Exception &e)
9903  {
9904  ErrorLog(162, e.Message);
9905  }
9906 }
9907 // ---------------------------------------------------------------------------
9908 
9909 void __fastcall TInterface::StepForwardMenuItemClick(TObject *Sender)
9910 {
9911  try
9912  {
9913  TrainController->LogEvent("StepForwardMenuItemClick");
9914  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",StepForwardMenuItemClick");
9916  Train.SignallerStoppingFlag = false;
9917  Train.SignallerStopped = false;
9918  Train.StoppedAtLocation = false; // may have started at station in signaller mode and also at a red signal, in this case both SignallerStopped
9919  // and StoppedAtLocation are set but the background colour stays pale green for station, not signal,
9920  // since no need to alert the user
9921  Train.StoppedAfterSPAD = false; // in case had been set
9922  Train.SPADFlag = false;
9923  Train.StepForwardFlag = true;
9924  Train.AllowedToPassRedSignal = true; // in case at a signal, will clear when half-way into next element whether a signal or not
9925  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9927  Train.LogAction(32, Train.HeadCode, "", SignallerStepForward, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
9928  int NextElementPos = -1;
9929 // addition for v1.3.2 due to Carwyn Thomas error: can't select StepForwardMenuItem if exiting at a continuation but leave this in anyway
9930  int NextEntryPos = -1; // ---ditto---
9931  if(Train.LeadElement > -1) // ---ditto---
9932  { // ---ditto---
9933  NextElementPos = Track->TrackElementAt(804, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
9934  NextEntryPos = Track->TrackElementAt(805, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
9935  } // ---ditto---
9936  if((NextElementPos > -1) && (NextEntryPos > -1))
9937  { // call this after StepForwardFlag set
9938  Train.EntrySpeed = 0;
9940  Train.FirstHalfMove = true;
9941  Train.SetTrainMovementValues(20, NextElementPos, NextEntryPos); // NextElement is the element to be entered
9942  }
9943  Utilities->CallLogPop(1800);
9944  }
9945  catch(const Exception &e)
9946  {
9947  ErrorLog(163, e.Message);
9948  }
9949 }
9950 
9951 // ---------------------------------------------------------------------------
9952 
9953 void __fastcall TInterface::RemoveTrainMenuItemClick(TObject *Sender)
9954 {
9955  try
9956  {
9957  TrainController->LogEvent("RemoveTrainMenuItemClick");
9958  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RemoveTrainMenuItemClick");
9960  if((!Train.Derailed) && (!Train.Crashed))
9961  {
9962  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
9964  UnicodeString Message = UnicodeString(Train.HeadCode) + " will be removed from the railway - proceed?";
9965  int button = Application->MessageBox(Message.c_str(), L"Please confirm", MB_YESNO);
9966  TrainController->BaseTime = TDateTime::CurrentDateTime();
9968  if(button == IDNO)
9969  {
9970  Utilities->CallLogPop(1801);
9971  return;
9972  }
9973  }
9974  Train.SignallerStoppingFlag = false;
9975  Train.TrainGone = true; // will be removed by TTrainController::Operate
9976  Train.SignallerRemoved = true;
9977  Train.TrainDataEntryPtr->TrainOperatingDataVector.at(Train.RepeatNumber).RunningEntry = Exited;
9978  AnsiString LocName = "";
9979  if(Train.LeadElement > -1)
9980  {
9981  LocName = Track->TrackElementAt(641, Train.LeadElement).ActiveTrackElementName;
9982  }
9983  if((LocName == "") && (Train.MidElement > -1))
9984  {
9985  LocName = Track->TrackElementAt(642, Train.MidElement).ActiveTrackElementName;
9986  }
9987  if((LocName == "") && Train.LeadElement > -1)
9988  {
9989  LocName = Track->TrackElementAt(643, Train.LeadElement).ElementID;
9990  }
9991  if((LocName == "") && (Train.MidElement > -1))
9992  {
9993  LocName = Track->TrackElementAt(644, Train.MidElement).ElementID;
9994  }
9995  TTrackElement *TrackElementPtr;
9996  int RouteNumber;
9997  TAllRoutes::TRouteType RouteType;
9998  if(Train.LeadElement > -1)
9999  {
10000  TrackElementPtr = &(Track->TrackElementAt(673, Train.LeadElement));
10001  // remove TrainIDs from track element, added at v2.4.0
10002  if(TrackElementPtr->TrackType == Bridge)
10003  {
10004  if(Train.LeadExitPos > 1)
10005  {
10006  TrackElementPtr->TrainIDOnBridgeTrackPos23 = -1;
10007  }
10008  else
10009  {
10010  TrackElementPtr->TrainIDOnBridgeTrackPos01 = -1;
10011  }
10012  }
10013  else
10014  {
10015  TrackElementPtr->TrainIDOnElement = -1;
10016  }
10017  // reset any CallingOnSet flags for signals, if facing wrong way doesn't matter, shouldn't be set anyay
10018  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
10019  {
10020  TrackElementPtr->CallingOnSet = false;
10021  Track->PlotSignal(6, *TrackElementPtr, Display);
10022  }
10023 // [added at v1.3.0] here check if on an automatic signals route and if so reset signals for the entire route from the
10024 // start of the route - after the train has been removed, use LeadElement and also MidElement (if no autosigs route at LeadElement) just to be sure
10025  RouteType = AllRoutes->GetRouteTypeAndNumber(27, Train.LeadElement, Train.LeadEntryPos, RouteNumber);
10026  if(RouteType == TAllRoutes::AutoSigsRoute)
10027  {
10030  }
10031 // end of addition
10032  }
10033  if(Train.MidElement > -1)
10034  {
10035  TrackElementPtr = &(Track->TrackElementAt(674, Train.MidElement));
10036  // remove TrainIDs from track element, added at v2.4.0
10037  if(TrackElementPtr->TrackType == Bridge)
10038  {
10039  if(Train.MidExitPos > 1)
10040  {
10041  TrackElementPtr->TrainIDOnBridgeTrackPos23 = -1;
10042  }
10043  else
10044  {
10045  TrackElementPtr->TrainIDOnBridgeTrackPos01 = -1;
10046  }
10047  }
10048  else
10049  {
10050  TrackElementPtr->TrainIDOnElement = -1;
10051  }
10052  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
10053  {
10054  TrackElementPtr->CallingOnSet = false;
10055  Track->PlotSignal(7, *TrackElementPtr, Display);
10056  }
10057 // [added at v1.3.0 as above]
10059  {
10060  RouteType = AllRoutes->GetRouteTypeAndNumber(28, Train.MidElement, Train.MidEntryPos, RouteNumber);
10061  if(RouteType == TAllRoutes::AutoSigsRoute)
10062  {
10065  }
10066  }
10067 // end of addition
10068  }
10069  if(Train.LeadElement > -1)
10070  // addition for v1.3.2 after Carwyn Thomas fault reported 24/05/15 - need to check if exiting at continuation (LeadElement == -1) as if so fails at next line
10071  {
10072  if(Track->TrackElementAt(675, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
10073  {
10074  TrackElementPtr = &(Track->TrackElementAt(676, Track->TrackElementAt(677, Train.LeadElement).Conn[Train.LeadExitPos]));
10075  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
10076  {
10077  TrackElementPtr->CallingOnSet = false;
10078  Track->PlotSignal(8, *TrackElementPtr, Display);
10079  }
10080  }
10081  }
10082  Train.LogAction(5, Train.HeadCode, "", RemoveTrain, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10083  if(Train.ActionVectorEntryPtr->Command != "Frh") // if remaining at location no point in sending 'failed to terminate' message
10084  {
10085  Train.SendMissedActionLogs(0, -1, Train.ActionVectorEntryPtr); // -1 is a marker for send messages for all remaining
10086  } // entries, including Fer if present
10087  Utilities->CallLogPop(1200);
10088  }
10089  catch(const Exception &e)
10090  {
10091  ErrorLog(164, e.Message);
10092  }
10093 }
10094 
10095 // ---------------------------------------------------------------------------
10096 
10097 void __fastcall TInterface::ErrorButtonClick(TObject *Sender)
10098  // to terminate after error message given
10099 {
10100  ErrorMessage->Visible = false;
10101  ErrorButton->Visible = false;
10102  Display->GetImage()->Visible = true;
10103  Application->Terminate();
10104 }
10105 
10106 // ---------------------------------------------------------------------------
10107 void __fastcall TInterface::PerformancePanelLabelStartDrag(TObject *Sender, TDragObject *&DragObject)
10108 {
10109  try
10110  {
10111  TrainController->LogEvent("PerformancePanelLabelStartDrag");
10112  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformancePanelLabelStartDrag");
10113  PerformancePanelDragStartX = Mouse->CursorPos.x - PerformancePanel->Left;
10114  PerformancePanelDragStartY = Mouse->CursorPos.y - PerformancePanel->Top;
10115  Utilities->CallLogPop(1202);
10116  }
10117  catch(const Exception &e)
10118  {
10119  ErrorLog(165, e.Message);
10120  }
10121 }
10122 // ---------------------------------------------------------------------------
10123 
10124 void __fastcall TInterface::FormClose(TObject *Sender, TCloseAction &Action)
10125 {
10126  try
10127  {
10128  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FormClose");
10130  {
10131  UnicodeString MessageStr =
10132  "Note that leaving the track unlinked will cause preferred directions to be lost on reloading. Prevent by linking the track then resaving. Do you still wish to exit?";
10133  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
10134  if(button == IDNO)
10135  {
10136  Action = caNone; // prevents form & application from closing
10137  Utilities->CallLogPop(1712);
10138  return;
10139  }
10140  }
10142  {
10143  UnicodeString MessStr = "";
10145  {
10146  MessStr = UnicodeString("The railway and the timetable have both changed, exit without saving either?");
10147  }
10148  else if(FileChangedFlag)
10149  {
10150  MessStr = UnicodeString("The railway has changed, exit without saving?");
10151  }
10152  else
10153  {
10154  MessStr = UnicodeString("The timetable has changed, exit without saving?");
10155  }
10156  int button = Application->MessageBox(MessStr.c_str(), L"Please confirm", MB_YESNO);
10157  if(button == IDNO)
10158  {
10159  Action = caNone; // prevents form & application from closing
10160  Utilities->CallLogPop(1133);
10161  return;
10162  }
10163  }
10164 
10165  if(Level1Mode == OperMode)
10166  {
10167  UnicodeString MessageStr = "Please note that the session will be lost if it hasn't been saved. Do you still wish to exit?";
10168  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
10170  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
10171  TrainController->BaseTime = TDateTime::CurrentDateTime();
10173  if(button == IDNO)
10174  {
10175  Action = caNone; // prevents form & application from closing
10176  Utilities->CallLogPop(969);
10177  return;
10178  }
10180  Utilities->PerformanceFile.close();
10181  }
10182  if((TempTTFileName != "") && FileExists(TempTTFileName))
10183  {
10184  DeleteFile(TempTTFileName);
10185  }
10186  Utilities->CallLogPop(971);
10187  }
10188  catch(const Exception &e)
10189  {
10190  ErrorLog(166, e.Message);
10191  }
10192 }
10193 
10194 // ---------------------------------------------------------------------------
10195 
10196 void __fastcall TInterface::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
10197 {
10198 // TrainController->LogEvent("FormKeyDown," + AnsiString(Key));
10199 // drop event log as have too many spurious entries
10200  try
10201  {
10202  if((Shift.Contains(ssAlt)) && (Shift.Contains(ssCtrl)))
10203  {
10204  if(Key == '2')
10205  {
10206  if(CallLogTickerLabel->Visible)
10207  {
10208  CallLogTickerLabel->Visible = false;
10209  }
10210  else
10211  {
10212  CallLogTickerLabel->Visible = true;
10213  }
10214  }
10215  else if(Key == '3')
10216  {
10217  if(DevelopmentPanel->Visible)
10218  {
10219  DevelopmentPanel->Visible = false;
10220  }
10221  else
10222  {
10223  DevelopmentPanel->Visible = true;
10224  DevelopmentPanel->BringToFront();
10225  }
10226  }
10227  else if(Key == '4')
10228  {
10229  TestFunction();
10230  }
10231  }
10232  else if(Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
10233  {
10234  CtrlKey = true;
10235  }
10236  else if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
10237  {
10238  ShiftKey = true;
10239  }
10240 
10241 // below added at v1.3.0 to allow keyboard scrolling as well as mouse button scrolling - see user suggestion on Features & Requests forum 30/09/12
10242 // the NonCTRLOrSHIFTKeyUpFlag prevents repeated viewpoint movements without keys being re-pressed
10243 // note that use the OnKeyDown event rather than OnKeyPress as suggested by the user so that the CTRL & SHIFT keys can be taken into account
10244 
10245 //at v2.4.2 the flag changed to LastNonCtrlOrShiftKeyDown to make condition specific to last key, because when a message given the key up event
10246 //is not seen as the form does not have focus, so with the flag no shortcut key will work on the first press, with this only the same shortcut key
10247 //won't work on first press and that is less likely to be used a second time on either side of the message
10248 
10249  if((Key != VK_SHIFT) && (Key != VK_CONTROL))
10250  {
10251  if(LastNonCtrlOrShiftKeyDown == Key) //same key still down rejected
10252  {
10253  return;
10254  }
10255  else
10256  {
10258  }
10259  }
10260 
10261  if(Key == VK_UP)
10262  {
10263  if(ScreenUpButton->Enabled)
10264  ScreenUpButton->Click();
10265  }
10266  else if(Key == VK_DOWN)
10267  {
10268  if(ScreenDownButton->Enabled)
10269  ScreenDownButton->Click();
10270  }
10271  else if(Key == VK_LEFT)
10272  {
10273  if(ScreenLeftButton->Enabled)
10274  ScreenLeftButton->Click();
10275  }
10276  else if(Key == VK_RIGHT)
10277  {
10278  if(ScreenRightButton->Enabled)
10279  ScreenRightButton->Click();
10280  }
10281  else if(Key == VK_HOME)
10282  {
10283  if(HomeButton->Enabled)
10284  HomeButton->Click();
10285  }
10286 // end of 1.3.0 addition
10287  else if(Key == VK_END) // added at v2.2.0 to toggle zoom using 'End' key
10288  {
10289  if(ZoomButton->Enabled)
10290  ZoomButton->Click();
10291  }
10292  else if(Key == VK_END) // added at v2.2.0 to toggle zoom using 'End' key
10293  {
10294  if(ZoomButton->Enabled)
10295  ZoomButton->Click();
10296  }
10297 
10298 //below added for v2.4.2 to add more keyboard shortcuts
10299  if(DistanceBox->Focused() || SpeedLimitBox->Focused() || MileEdit->Focused() || ChainEdit->Focused() || YardEdit->Focused() || SpeedEditBox2->Focused()
10300  || MTBFEditBox->Focused() || LocationNameTextBox->Focused() || TextBox->Focused() || PowerEditBox->Focused() || SpeedEditBox->Focused()
10301  || AddSubMinsBox->Focused() || OneEntryTimetableMemo->Focused())
10302  {// prevent letter keys interfering when these boxes have focus - many are mutually exclusive but include them all
10303  return;
10304  }
10305 
10306  if(Shift.Contains(ssShift) && !Shift.Contains(ssAlt) && !Shift.Contains(ssCtrl) && NewHomeButton->Enabled && NewHomeButton->Visible)
10307  {
10308  if(Level1Mode != TimetableMode && (Key == 'H' || Key == 'h'))//TimetablePanel uses Shift H too so disable this when it's in use
10309  {
10310  NewHomeButton->Click();
10311  }
10312  }
10313 
10314 //Operating panel
10315  if(Level1Mode == OperMode && OperatingPanel->Enabled && OperatingPanel->Visible && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
10316  { //use Shift.Contains(ssShift etc instead of ShiftKey as that not set if pressed second after Ctrl key pressed
10317  if(!Shift.Contains(ssCtrl))
10318  {
10319  if(OperateButton->Visible && OperateButton->Enabled)
10320  {
10321  if(Level2OperMode == Operating && (Key == 'P' || Key == 'p'))
10322  {
10323  OperateButton->Click();
10324  }
10325  else if((Level2OperMode == Paused || Level2OperMode == PreStart) && (Key == 'R' || Key == 'r'))
10326  {
10327  OperateButton->Click();
10328  }
10329  }
10330  if(PresetAutoSigRoutesButton->Visible && PresetAutoSigRoutesButton->Enabled && (Key == 'A' || Key == 'a'))
10331  {
10332  PresetAutoSigRoutesButton->Click();
10333  }
10334  if(PerformanceLogButton->Visible && PerformanceLogButton->Enabled && (Key == 'L' || Key == 'l'))
10335  {
10336  PerformanceLogButton->Click();
10337  }
10338  if(CallingOnButton->Visible && CallingOnButton->Enabled && (Key == 'O' || Key == 'o'))
10339  {
10340  CallingOnButton->Click();
10341  }
10342  if(OperatorActionButton->Visible && OperatorActionButton->Enabled && (Key == 'D' || Key == 'd'))
10343  {
10344  OperatorActionButton->Click();
10345  }
10346  if(RouteCancelButton->Visible && RouteCancelButton->Enabled && (Key == 'C' || Key == 'c'))
10347  {
10348  RouteCancelButton->Click();
10349  }
10350  if(TTClockAdjButton->Visible && TTClockAdjButton->Enabled && (Key == 'T' || Key == 't'))
10351  {
10352  TTClockAdjButton->Click();
10353  }
10354  if(AutoSigsButton->Visible && AutoSigsButton->Enabled && Key == '1') //route buttons - autosigs
10355  {
10356  AutoSigsButton->Click();
10357  }
10358  if(SigPrefButton->Visible && SigPrefButton->Enabled && Key == '2') //route buttons - prefdir
10359  {
10360  SigPrefButton->Click();
10361  }
10362  if(UnrestrictedButton->Visible && UnrestrictedButton->Enabled && Key == '3') //route buttons - unrestricted
10363  {
10364  UnrestrictedButton->Click();
10365  }
10366  if(ExitOperationButton->Visible && ExitOperationButton->Enabled && Key == '\x1b')
10367  {
10368  ExitOperationButton->Click();
10369  }
10370  }
10371  else //CtrlKey down
10372  {
10373  if(SaveSessionButton->Visible && SaveSessionButton->Enabled)
10374  {
10375  SaveMenuItem->ShortCut = 0; //It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
10376  if(Key == 'S' || Key == 's')//so this will never execute
10377  {
10378  SaveSessionButton->Click();
10379  }
10380  }
10381  }
10382  }
10383 
10384 //Timetable clock adjust panel
10385  if(Level1Mode == OperMode && TTClockAdjPanel->Enabled && TTClockAdjPanel->Visible && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
10386  { //use Shift.Contains(ssShift etc instead of ShiftKey as that not set if pressed second after Ctrl key pressed
10387  if(Shift.Contains(ssShift))
10388  {
10389  if(TTClockExitButton->Visible && TTClockExitButton->Enabled && (Key == 'A' || Key == 'a'))
10390  {
10391  TTClockExitButton->Click();
10392  }
10393  if(TTClockResetButton->Visible && TTClockResetButton->Enabled && (Key == 'R' || Key == 'r'))
10394  {
10395  TTClockResetButton->Click();
10396  }
10397  }
10398  }
10399 
10400 //Track build panel
10401  if((Level1Mode == TrackMode) && TrackBuildPanel->Visible && TrackBuildPanel->Enabled)
10402  {
10403  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
10404  {
10405  if(AddTrackButton->Visible && AddTrackButton->Enabled && (Key == 'A' || Key == 'a')) //add/remove track elements
10406  {
10407  AddTrackButton->Click();
10408  }
10409  if(SigAspectButton->Visible && SigAspectButton->Enabled && (Key == 'S' || Key == 's')) //cycle through signal aspects
10410  {
10411  SigAspectButton->Click();
10412  }
10413  if(TrackOKButton->Visible && TrackOKButton->Enabled && (Key == 'L' || Key == 'l')) //link track
10414  {
10415  TrackOKButton->Click();
10416  }
10417  if(FontButton->Visible && FontButton->Enabled && (Key == 'F' || Key == 'f')) //change font
10418  {
10419  FontButton->Click();
10420  }
10421  if(LocationNameButton->Visible && LocationNameButton->Enabled && (Key == 'N' || Key == 'n')) //name locations
10422  {
10423  LocationNameButton->Click();
10424  }
10425  if(SetLengthsButton->Visible && SetLengthsButton->Enabled && (Key == 'D' || Key == 'd')) //set distances/speeds
10426  {
10427  SetLengthsButton->Click();
10428  }
10429  if(AddTextButton->Visible && AddTextButton->Enabled && (Key == 'T' || Key == 't')) //add text
10430  {
10431  AddTextButton->Click();
10432  }
10433  if(ScreenGridButton->Visible && ScreenGridButton->Enabled && (Key == 'G' || Key == 'g')) //toggle grid
10434  {
10435  ScreenGridButton->Click();
10436  }
10437  if(MoveTextOrGraphicButton->Visible && MoveTextOrGraphicButton->Enabled && (Key == 'M' || Key == 'm')) //move text or graphic
10438  {
10439  MoveTextOrGraphicButton->Click();
10440  }
10441  if(UserGraphicButton->Visible && UserGraphicButton->Enabled && (Key == 'I' || Key == 'i')) //insert image
10442  {
10443  UserGraphicButton->Click();
10444  }
10445  if(SetGapsButton->Visible && SetGapsButton->Enabled && (Key == 'J' || Key == 'j')) //join gaps
10446  {
10447  SetGapsButton->Click();
10448  }
10449  }
10450  if(Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
10451  {
10452  if(SaveRailwayTBPButton->Visible && SaveRailwayTBPButton->Enabled) //save railway in trackbuild mode
10453  {
10454  SaveMenuItem->ShortCut = 0; //It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
10455  if(Key == 'S' || Key == 's')//so this will never execute
10456  {
10457  SaveRailwayTBPButton->Click();
10458  }
10459  }
10460  }
10461  if(!Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
10462  {
10463  if((ExitTrackButton->Visible && ExitTrackButton->Enabled) && Key == '\x1b') //escape key
10464  {
10465  ExitTrackButton->Click();
10466  }
10467  }
10468  }
10469 
10470 //PrefDir panel
10471  if(Level1Mode == PrefDirMode && PrefDirPanel->Visible && PrefDirPanel->Enabled && !Shift.Contains(ssAlt))
10472  {
10473  if(!Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
10474  {
10475  if((ExitPrefDirButton->Visible && ExitPrefDirButton->Enabled) && Key == '\x1b') //escape key
10476  {
10477  ExitPrefDirButton->Click();
10478  }
10479  }
10480  if(!Shift.Contains(ssShift) && Shift.Contains(ssCtrl))
10481  {
10482  if(SaveRailwayPDPButton->Visible && SaveRailwayPDPButton->Enabled)
10483  {
10484  SaveMenuItem->ShortCut = 0; //It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
10485  if(Key == 'S' || Key == 's')//so this will never execute
10486  {
10487  SaveRailwayPDPButton->Click();
10488  }
10489  }
10490  }
10491  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
10492  {
10493  if(AddPrefDirButton->Visible && AddPrefDirButton->Enabled && (Key == 'A' || Key == 'a')) //add pref dir
10494  {
10495  AddPrefDirButton->Click();
10496  }
10497  if(DeleteOnePrefDirButton->Visible && DeleteOnePrefDirButton->Enabled && (Key == 'D' || Key == 'd')) //delete one pref dir
10498  {
10499  DeleteOnePrefDirButton->Click();
10500  }
10501  if(DeleteAllPrefDirButton->Visible && DeleteAllPrefDirButton->Enabled && (Key == 'C' || Key == 'c')) //delete all pref dirs
10502  {
10503  DeleteAllPrefDirButton->Click();
10504  }
10505  }
10506  }
10507 //Note that save button in BaseMode is handled by Ctrl S from the File menu
10508 
10509 //Timetable panel
10510  if(Level1Mode == TimetableMode && TimetablePanel->Visible && TimetablePanel->Enabled && !Shift.Contains(ssAlt))
10511  {
10512  if(!Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
10513  {
10514  if(ExitTTModeButton->Visible && ExitTTModeButton->Enabled && Key == '\x1b') //escape key
10515  {
10516  ExitTTModeButton->Click();
10517  }
10518  }
10519  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl)) //show/hide timetable edit panel
10520  {
10521  if(ShowHideTTButton->Visible && ShowHideTTButton->Enabled)
10522  {
10523  if(!TimetableEditPanel->Visible)
10524  {
10525  if(Key == 'S' || Key == 's')
10526  {
10527  ShowHideTTButton->Click();
10528  }
10529  }
10530  else if(Key == 'H' || Key == 'h')
10531  {
10532  ShowHideTTButton->Click();
10533  }
10534  }
10535  }
10536  }
10537 
10538 //Timetable edit panel
10539  if(Level1Mode == TimetableMode && TimetableEditPanel->Visible && TimetableEditPanel->Enabled && !Shift.Contains(ssAlt))
10540  {
10541  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
10542  {
10543  if(PreviousTTEntryButton->Enabled && (Key == 'L' || Key == 'l'))
10544  {
10545  PreviousTTEntryButton->Click();
10546  }
10547  if(NextTTEntryButton->Enabled && (Key == 'N' || Key == 'n'))
10548  {
10549  NextTTEntryButton->Click();
10550  }
10551  if(MoveTTEntryUpButton->Enabled && (Key == 'U' || Key == 'u'))
10552  {
10553  MoveTTEntryUpButton->Click();
10554  }
10555  if(MoveTTEntryDownButton->Enabled && (Key == 'D' || Key == 'd'))
10556  {
10557  MoveTTEntryDownButton->Click();
10558  }
10559  if(CopyTTEntryButton->Enabled && (Key == 'C' || Key == 'c'))
10560  {
10561  CopyTTEntryButton->Click();
10562  }
10563  if(CutTTEntryButton->Enabled && (Key == 'X' || Key == 'x'))
10564  {
10565  CutTTEntryButton->Click();
10566  }
10567  if(PasteTTEntryButton->Enabled && (Key == 'P' || Key == 'p'))
10568  {
10569  PasteTTEntryButton->Click();
10570  }
10571  if(DeleteTTEntryButton->Enabled && (Key == 'E' || Key == 'e'))
10572  {
10573  DeleteTTEntryButton->Click();
10574  }
10575 /* if(SaveTTEntryButton->Enabled && (Key == 'E' || Key == 'e')) //can't have save while editing entry as adds the letter to the entry
10576  {
10577  SaveTTEntryButton->Click();
10578  }
10579  if(CancelTTActionButton->Enabled && (Key == 'K' || Key == 'k')) //can't have cancel while editing entry as adds the letter to the entry
10580  {
10581  CancelTTActionButton->Click();
10582  }
10583 */
10584  if(NewTTEntryButton->Enabled && (Key == 'I' || Key == 'i'))
10585  {
10586  NewTTEntryButton->Click();
10587  }
10588  if(AZOrderButton->Enabled && (Key == 'Z' || Key == 'z'))
10589  {
10590  AZOrderButton->Click();
10591  }
10592  if(AddMinsButton->Enabled && (Key == 'M' || Key == 'm'))
10593  {
10594  AddMinsButton->Click();
10595  }
10596  if(SubMinsButton->Enabled && (Key == 'B' || Key == 'b'))
10597  {
10598  SubMinsButton->Click();
10599  }
10600  if(TTServiceSyntaxCheckButton->Enabled && (Key == 'Q' || Key == 'q'))
10601  {
10602  TTServiceSyntaxCheckButton->Click();
10603  }
10604  if(ValidateTimetableButton->Enabled && (Key == 'V' || Key == 'v'))
10605  {
10606  ValidateTimetableButton->Click();
10607  }
10608  if(SaveTTButton->Enabled && (Key == 'T' || Key == 't'))
10609  {
10610  SaveTTButton->Click();
10611  }
10612  if(SaveTTAsButton->Enabled && (Key == 'A' || Key == 'a'))
10613  {
10614  SaveTTAsButton->Click();
10615  }
10616  if(RestoreTTButton->Enabled && (Key == 'R' || Key == 'r'))
10617  {
10618  RestoreTTButton->Click();
10619  }
10620  if(ExportTTButton->Enabled && (Key == 'O' || Key == 'o'))
10621  {
10622  ExportTTButton->Click();
10623  }
10624  }
10625  }
10626 
10627 
10628 //Information menu
10629  if(FloatingInfoMenu->Enabled && !Shift.Contains(ssAlt) && Shift.Contains(ssCtrl) && Shift.Contains(ssShift))
10630  {
10631  if(Key == 'I' || Key == 'i') //toggle track info
10632  {
10633  TrackInfoOnOffMenuItem->Click();
10634  }
10635  else if(TrainInfoMenuItem->Enabled)
10636  {
10637  if(Key == 'S' || Key == 's') //toggle train status info
10638  {
10640  }
10641  else if(Key == 'T' || Key == 't') //toggle train timetable info
10642  {
10643  TrainTTInfoOnOffMenuItem->Click();
10644  }
10645 
10646  }
10647  }
10648 //end of 2.4.2 addition
10649 
10650  }
10651  catch(const Exception &e)
10652  {
10653  ErrorLog(167, e.Message);
10654  }
10655 }
10656 
10657 // ---------------------------------------------------------------------------
10658 
10659 void __fastcall TInterface::FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
10660 {
10661  if((Key != VK_SHIFT) && (Key != VK_CONTROL))
10662  LastNonCtrlOrShiftKeyDown = -1; //reset value to no key down
10663  CtrlKey = false;
10664  ShiftKey = false;
10665  SaveMenuItem->ShortCut = 16467; //restore Ctrl S for save menu in case set to 0 in FormKeyDown
10666 }
10667 
10668 // ---------------------------------------------------------------------------
10669 
10670 void __fastcall TInterface::OutputLog1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10671 {
10672  if((Button == mbRight) && Level2OperMode == Operating)
10673  {
10674  OutputLog1->Caption = "";
10675  }
10676 }
10677 
10678 // ---------------------------------------------------------------------------
10679 
10680 void __fastcall TInterface::OutputLog2MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10681 {
10682  if((Button == mbRight) && Level2OperMode == Operating)
10683  {
10684  OutputLog2->Caption = "";
10685  }
10686 }
10687 // ---------------------------------------------------------------------------
10688 
10689 void __fastcall TInterface::OutputLog3MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10690 {
10691  if((Button == mbRight) && Level2OperMode == Operating)
10692  {
10693  OutputLog3->Caption = "";
10694  }
10695 }
10696 
10697 // ---------------------------------------------------------------------------
10698 
10699 void __fastcall TInterface::OutputLog4MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10700 {
10701  if((Button == mbRight) && Level2OperMode == Operating)
10702  {
10703  OutputLog4->Caption = "";
10704  }
10705 }
10706 
10707 // ---------------------------------------------------------------------------
10708 
10709 void __fastcall TInterface::OutputLog5MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10710 {
10711  if((Button == mbRight) && Level2OperMode == Operating)
10712  {
10713  OutputLog5->Caption = "";
10714  }
10715 }
10716 // ---------------------------------------------------------------------------
10717 
10718 void __fastcall TInterface::OutputLog6MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10719 {
10720  if((Button == mbRight) && Level2OperMode == Operating)
10721  {
10722  OutputLog6->Caption = "";
10723  }
10724 }
10725 
10726 // ---------------------------------------------------------------------------
10727 
10728 void __fastcall TInterface::OutputLog7MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10729 {
10730  if((Button == mbRight) && Level2OperMode == Operating)
10731  {
10732  OutputLog7->Caption = "";
10733  }
10734 }
10735 
10736 // ---------------------------------------------------------------------------
10737 
10738 void __fastcall TInterface::OutputLog8MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10739 {
10740  if((Button == mbRight) && Level2OperMode == Operating)
10741  {
10742  OutputLog8->Caption = "";
10743  }
10744 }
10745 
10746 // ---------------------------------------------------------------------------
10747 
10748 void __fastcall TInterface::OutputLog9MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10749 {
10750  if((Button == mbRight) && Level2OperMode == Operating)
10751  {
10752  OutputLog9->Caption = "";
10753  }
10754 }
10755 
10756 // ---------------------------------------------------------------------------
10757 
10758 void __fastcall TInterface::OutputLog10MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10759 {
10760  if((Button == mbRight) && Level2OperMode == Operating)
10761  {
10762  OutputLog10->Caption = "";
10763  }
10764 }
10765 
10766 // ---------------------------------------------------------------------------
10767 
10768 void __fastcall TInterface::AboutMenuItemClick(TObject *Sender)
10769 {
10770  try
10771  {
10772  if((Level1Mode == OperMode) && (Level2OperMode != PreStart))
10773  // if PreStart leave as is [Modified at v1.2.0 - formerly just 'if((Level1Mode == OperMode)']
10774  {
10776  SetLevel2OperMode(3);
10777  MasterClock->Enabled = false;
10778  }
10779  AboutForm->ShowModal();
10780  }
10781  catch(const Exception &e)
10782  {
10783  ErrorLog(168, e.Message);
10784  }
10785 }
10786 
10787 // ---------------------------------------------------------------------------
10788 
10789 void __fastcall TInterface::OpenHelpMenuItemClick(TObject *Sender)
10790 {
10791  try
10792  {
10793  // Helpfile allocated during construction of Interface
10794  Application->HelpKeyword(u"Introduction"); // added at v2.0.0 for .chm help file
10795  }
10796  catch(const Exception &e)
10797  {
10798  ErrorLog(175, e.Message);
10799  }
10800 }
10801 
10802 // ---------------------------------------------------------------------------
10803 
10804 void __fastcall TInterface::RailwayWebSiteMenuItemClick(TObject *Sender)
10805 {
10806  const UnicodeString Link = "http://www.railwayoperationsimulator.com";
10807  ::ShellExecute(Handle, NULL, (Link).c_str(), NULL, NULL, SW_SHOWNORMAL);
10808 }
10809 
10810 // ---------------------------------------------------------------------------
10811 
10812 void __fastcall TInterface::BlackBgndMenuItemClick(TObject *Sender)
10813 {
10814  try
10815  {
10816  TrainController->LogEvent("BlackBgndMenuItemClick");
10817  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BlackBgndMenuItemClick");
10818  std::ofstream ColFile((CurDir + "\\Background.col").c_str());
10819  if(ColFile.fail())
10820  {
10821  // ShowMessage("Failed to store colour file, program will default to a black background when next loaded");
10822  // no need for message as will revert to black by default
10823  }
10824  else
10825  {
10826  Utilities->SaveFileString(ColFile, "black");
10827  ColFile.close(); // added at v2.3.0, should have been in earlier
10828  }
10829  TColor OldTransparentColour = Utilities->clTransparent;
10830  Utilities->clTransparent = TColor(0);
10831  SelectBitmap->TransparentColor = Utilities->clTransparent;
10833  TextBox->Color = clB3G3R3;
10835 
10836  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
10837  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
10838  Level1Mode = BaseMode;
10839  SetLevel1Mode(128);
10840  Utilities->CallLogPop(1797);
10841  }
10842  catch(const Exception &e)
10843  {
10844  ErrorLog(170, e.Message);
10845  }
10846 }
10847 
10848 // ---------------------------------------------------------------------------
10849 
10850 void __fastcall TInterface::WhiteBgndMenuItemClick(TObject *Sender)
10851 {
10852  try
10853  {
10854  TrainController->LogEvent("WhiteBgndMenuItemClick");
10855  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",WhiteBgndMenuItemClick");
10856  std::ofstream ColFile((CurDir + "\\Background.col").c_str());
10857  if(ColFile.fail())
10858  {
10859  ShowMessage("Failed to store colour file, program will default to a black background when next loaded");
10860  }
10861  else
10862  {
10863  Utilities->SaveFileString(ColFile, "white");
10864  ColFile.close(); // added at v2.3.0, should have been in earlier
10865  }
10866  TColor OldTransparentColour = Utilities->clTransparent;
10867  Utilities->clTransparent = TColor(0xFFFFFF);
10868  SelectBitmap->TransparentColor = Utilities->clTransparent;
10870  TextBox->Color = clB5G5R5;
10872 
10873  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
10874  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
10875  Level1Mode = BaseMode;
10876  SetLevel1Mode(129);
10877  Utilities->CallLogPop(1798);
10878  }
10879  catch(const Exception &e)
10880  {
10881  ErrorLog(171, e.Message);
10882  }
10883 }
10884 
10885 // ---------------------------------------------------------------------------
10886 
10887 void __fastcall TInterface::BlueBgndMenuItemClick(TObject *Sender)
10888 {
10889  try
10890  {
10891  TrainController->LogEvent("BlueBgndMenuItemClick");
10892  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BlueBgndMenuItemClick");
10893  std::ofstream ColFile((CurDir + "\\Background.col").c_str());
10894  if(ColFile.fail())
10895  {
10896  ShowMessage("Failed to store colour file, program will default to a black background when next loaded");
10897  }
10898  else
10899  {
10900  Utilities->SaveFileString(ColFile, "blue");
10901  ColFile.close(); // added at v2.3.0, should have been in earlier
10902  }
10903  TColor OldTransparentColour = Utilities->clTransparent;
10904  Utilities->clTransparent = TColor(0x330000);
10905  SelectBitmap->TransparentColor = Utilities->clTransparent;
10907  TextBox->Color = clB3G3R3;
10909 
10910  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
10911  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
10912  Level1Mode = BaseMode;
10913  SetLevel1Mode(130);
10914  Utilities->CallLogPop(1799);
10915  }
10916  catch(const Exception &e)
10917  {
10918  ErrorLog(172, e.Message);
10919  }
10920 }
10921 
10922 // ---------------------------------------------------------------------------
10923 
10924 void __fastcall TInterface::SpeedToggleButtonClick(TObject *Sender)
10925 {
10926  if(SpeedTopLabel->Caption == "mph")
10927  {
10928  SpeedTopLabel->Caption = "km/h";
10929  SpeedBottomLabel->Caption = "mph";
10930  }
10931  else
10932  {
10933  SpeedTopLabel->Caption = "mph";
10934  SpeedBottomLabel->Caption = "km/h";
10935  }
10936  // swap values to match toggle state
10937  UnicodeString SavedTopValue = SpeedEditBox->Text;
10938  UnicodeString SavedBottomValue = SpeedVariableLabel->Caption;
10939 
10940  SpeedEditBox->Text = SavedBottomValue;
10941  SpeedVariableLabel->Caption = SavedTopValue;
10942 }
10943 // ---------------------------------------------------------------------------
10944 
10945 void __fastcall TInterface::SpeedToggleButton2Click(TObject *Sender)
10946 {
10947  if(SpeedTopLabel2->Caption == "mph")
10948  {
10949  SpeedTopLabel2->Caption = "km/h";
10950  SpeedBottomLabel2->Caption = "mph";
10951  }
10952  else
10953  {
10954  SpeedTopLabel2->Caption = "mph";
10955  SpeedBottomLabel2->Caption = "km/h";
10956  }
10957  // swap values to match toggle state
10958  UnicodeString SavedTopValue = SpeedEditBox2->Text;
10959  UnicodeString SavedBottomValue = SpeedVariableLabel2->Caption;
10960 
10961  SpeedEditBox2->Text = SavedBottomValue;
10962  SpeedVariableLabel2->Caption = SavedTopValue;
10963 }
10964 // ---------------------------------------------------------------------------
10965 
10966 void __fastcall TInterface::SpeedEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
10967 {
10968  try
10969  {
10970  TrainController->LogEvent("SpeedEditBoxKeyUp," + AnsiString(Key));
10971  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedEditBoxKeyUp," + AnsiString(Key));
10972  bool ErrorFlag = false, TooBigFlag = false;
10973  if(SpeedEditBox->Text.Length() > 0)
10974  {
10975  if(SpeedEditBox->Text.Length() > 5)
10976  {
10977  TooBigFlag = true;
10978  }
10979  for(int x = 1; x <= SpeedEditBox->Text.Length(); x++)
10980  {
10981  if((SpeedEditBox->Text[x] < '0') || (SpeedEditBox->Text[x] > '9'))
10982  {
10983  SpeedVariableLabel->Caption = "Entry error";
10984  ErrorFlag = true;
10985  break;
10986  }
10987  if(TooBigFlag)
10988  {
10989  SpeedVariableLabel->Caption = "Too big";
10990  break;
10991  }
10992  }
10993  if(!ErrorFlag && !TooBigFlag)
10994  {
10995 /*
10996  1 mph = 1.609344 km/h
10997  1 km/h = 0.621371 mph
10998 */
10999  if(SpeedTopLabel->Caption == "mph")
11000  {
11001  // do mph-to-km/h conversion
11002  int MPH = SpeedEditBox->Text.ToInt();
11003  int KPH = (MPH * 1.609344) + 0.5;
11004  SpeedVariableLabel->Caption = UnicodeString(KPH);
11005  }
11006  else
11007  {
11008  // do km/h-to-mph conversion
11009  int KPH = SpeedEditBox->Text.ToInt();
11010  int MPH = (KPH * 0.621371) + 0.5;
11011  SpeedVariableLabel->Caption = UnicodeString(MPH);
11012  }
11013  }
11014  }
11015  else
11016  {
11017  SpeedVariableLabel->Caption = "";
11018  }
11019  Utilities->CallLogPop(1865);
11020  }
11021  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
11022  {
11023  SpeedVariableLabel->Caption = "Entry error";
11024  }
11025  catch(const Exception &e)
11026  {
11027  ErrorLog(176, e.Message);
11028  }
11029 }
11030 
11031 // ---------------------------------------------------------------------------
11032 
11033 void __fastcall TInterface::PowerToggleButtonClick(TObject *Sender)
11034 {
11035  if(PowerTopLabel->Caption == "HP")
11036  {
11037  PowerTopLabel->Caption = "kW";
11038  PowerBottomLabel->Caption = "HP";
11039  }
11040  else
11041  {
11042  PowerTopLabel->Caption = "HP";
11043  PowerBottomLabel->Caption = "kW";
11044  }
11045  // swap values to match toggle state
11046  UnicodeString SavedTopValue = PowerEditBox->Text;
11047  UnicodeString SavedBottomValue = PowerVariableLabel->Caption;
11048 
11049  PowerEditBox->Text = SavedBottomValue;
11050  PowerVariableLabel->Caption = SavedTopValue;
11051 }
11052 // ---------------------------------------------------------------------------
11053 
11054 void __fastcall TInterface::PowerEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11055 {
11056  try
11057  {
11058  TrainController->LogEvent("PowerEditBoxKeyUp," + AnsiString(Key));
11059  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PowerEditBoxKeyUp," + AnsiString(Key));
11060  bool ErrorFlag = false, TooBigFlag = false;
11061  if(PowerEditBox->Text.Length() > 0)
11062  {
11063  if(PowerEditBox->Text.Length() > 8)
11064  {
11065  TooBigFlag = true;
11066  }
11067  for(int x = 1; x <= PowerEditBox->Text.Length(); x++)
11068  {
11069  if((PowerEditBox->Text[x] < '0') || (PowerEditBox->Text[x] > '9'))
11070  {
11071  PowerVariableLabel->Caption = "Entry error";
11072  ErrorFlag = true;
11073  break;
11074  }
11075  if(TooBigFlag)
11076  {
11077  PowerVariableLabel->Caption = "Too big";
11078  break;
11079  }
11080  }
11081  if(!ErrorFlag && !TooBigFlag)
11082  {
11083 /*
11084  1 kW = 1.340482574 HP
11085  1 HP = 0.745699872 kW
11086 */
11087  if(PowerTopLabel->Caption == "HP")
11088  {
11089  // do HP-to-kW conv
11090  int HP = PowerEditBox->Text.ToInt();
11091  int KW = (HP * 0.745699872) + 0.5;
11092  PowerVariableLabel->Caption = UnicodeString(KW);
11093  }
11094  else
11095  {
11096  // do kW-to-HP conv
11097  int KW = PowerEditBox->Text.ToInt();
11098  int HP = (KW * 1.340482574) + 0.5;
11099  PowerVariableLabel->Caption = UnicodeString(HP);
11100  }
11101  }
11102  }
11103  else
11104  {
11105  PowerVariableLabel->Caption = "";
11106  }
11107  Utilities->CallLogPop(1868);
11108  }
11109  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
11110  {
11111  PowerVariableLabel->Caption = "Entry error";
11112  }
11113  catch(const Exception &e)
11114  {
11115  ErrorLog(179, e.Message);
11116  }
11117 }
11118 // ---------------------------------------------------------------------------
11119 
11120 void __fastcall TInterface::SpeedEditBox2KeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11121 {
11122  try
11123  {
11124  TrainController->LogEvent("SpeedEditBox2KeyUp," + AnsiString(Key));
11125  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedEditBox2KeyUp," + AnsiString(Key));
11126  bool ErrorFlag = false, TooBigFlag = false;
11127  if(SpeedEditBox2->Text.Length() > 0)
11128  {
11129  if(SpeedEditBox2->Text.Length() > 5)
11130  {
11131  TooBigFlag = true;
11132  }
11133  for(int x = 1; x <= SpeedEditBox2->Text.Length(); x++)
11134  {
11135  if((SpeedEditBox2->Text[x] < '0') || (SpeedEditBox2->Text[x] > '9'))
11136  {
11137  SpeedVariableLabel2->Caption = "Entry error";
11138  ErrorFlag = true;
11139  break;
11140  }
11141  if(TooBigFlag)
11142  {
11143  SpeedVariableLabel2->Caption = "Too big";
11144  break;
11145  }
11146  }
11147  if(!ErrorFlag && !TooBigFlag)
11148  {
11149 /*
11150  1 mph = 1.609344 km/h
11151  1 km/h = 0.621371 mph
11152 */
11153  if(SpeedTopLabel2->Caption == "mph")
11154  {
11155  // do mph-to-km/h conversion
11156  int MPH = SpeedEditBox2->Text.ToInt();
11157  int KPH = (MPH * 1.609344) + 0.5;
11158  SpeedVariableLabel2->Caption = AnsiString(KPH);
11159  }
11160  else
11161  {
11162  // do km/h-to-mph conversion
11163  int KPH = SpeedEditBox2->Text.ToInt();
11164  int MPH = (KPH * 0.621371) + 0.5;
11165  SpeedVariableLabel2->Caption = AnsiString(MPH);
11166  }
11167  }
11168  }
11169  else
11170  {
11171  SpeedVariableLabel2->Caption = "";
11172  }
11173  Utilities->CallLogPop(1866);
11174  }
11175  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
11176  {
11177  SpeedVariableLabel2->Caption = "Entry error";
11178  }
11179  catch(const Exception &e)
11180  {
11181  ErrorLog(177, e.Message);
11182  }
11183 }
11184 
11185 // ---------------------------------------------------------------------------
11186 
11187 void __fastcall TInterface::LengthEditKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11188 {
11189  try
11190  {
11191  TrainController->LogEvent("LengthEditKeyUp," + AnsiString(Key));
11192  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthEditKeyUp," + AnsiString(Key));
11193  bool ErrorFlag = false, TooLongFlag = false;
11194  if((MileEdit->Text.Length() > 0) && (MileEdit->Text.Length() < 6))
11195  {
11196  for(int x = 1; x <= MileEdit->Text.Length(); x++)
11197  {
11198  if((MileEdit->Text[x] < '0') || (MileEdit->Text[x] > '9'))
11199  {
11200  MetreVariableLabel->Caption = "Entry error";
11201  ErrorFlag = true;
11202  break;
11203  }
11204  }
11205  }
11206  if((ChainEdit->Text.Length() > 0) && (ChainEdit->Text.Length() < 6))
11207  {
11208  for(int x = 1; x <= ChainEdit->Text.Length(); x++)
11209  {
11210  if((ChainEdit->Text[x] < '0') || (ChainEdit->Text[x] > '9'))
11211  {
11212  MetreVariableLabel->Caption = "Entry error";
11213  ErrorFlag = true;
11214  break;
11215  }
11216  }
11217  }
11218  if((YardEdit->Text.Length() > 0) && (YardEdit->Text.Length() < 6))
11219  {
11220  for(int x = 1; x <= YardEdit->Text.Length(); x++)
11221  {
11222  if((YardEdit->Text[x] < '0') || (YardEdit->Text[x] > '9'))
11223  {
11224  MetreVariableLabel->Caption = "Entry error";
11225  ErrorFlag = true;
11226  break;
11227  }
11228  }
11229  }
11230  if((MileEdit->Text.Length() > 5) || (ChainEdit->Text.Length() > 5) || (YardEdit->Text.Length() > 5))
11231  {
11232  TooLongFlag = true;
11233  MetreVariableLabel->Caption = "Too big";
11234  }
11235  if(!ErrorFlag && !TooLongFlag)
11236  {
11237  int Miles = 0, Chains = 0, Yards = 0, Metres = 0;
11238  if(MileEdit->Text.Length() > 0)
11239  {
11240  Miles = MileEdit->Text.ToInt();
11241  }
11242  if(ChainEdit->Text.Length() > 0)
11243  {
11244  Chains = ChainEdit->Text.ToInt();
11245  }
11246  if(YardEdit->Text.Length() > 0)
11247  {
11248  Yards = YardEdit->Text.ToInt();
11249  }
11250  Metres = int((Miles * 1609.344) + (Chains * 20.1168) + (Yards * 0.9144) + 0.5);
11251  MetreVariableLabel->Caption = AnsiString(Metres);
11252  }
11253  if((MileEdit->Text.Length() == 0) && (ChainEdit->Text.Length() == 0) && (YardEdit->Text.Length() == 0))
11254  {
11255  MetreVariableLabel->Caption = "";
11256  }
11257  Utilities->CallLogPop(1867);
11258  }
11259  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
11260  {
11261  MetreVariableLabel->Caption = "Entry error";
11262  }
11263  catch(const Exception &e)
11264  {
11265  ErrorLog(178, e.Message);
11266  }
11267 }
11268 
11269 // ---------------------------------------------------------------------------
11270 
11271 void __fastcall TInterface::TTClockAdjButtonClick(TObject *Sender)
11272 {
11273  try
11274  {
11275  TrainController->LogEvent("TTClockAdjButtonClick");
11276  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdjButtonClick");
11277 // Utilities->Clock2Stopped = true; // to keep panel buttons disabled, restarted on exit
11278  Display->HideWarningLog(0); //because this panel overwrites it
11279  TTClockAdjPanel->Visible = true;
11280  TTClockAdjButton->Enabled = false;
11281 /*
11282  OperatingPanelLabel->Caption = "Disabled"; all these now dealt with in ClockTimer2
11283  OperatingPanel->Enabled = false;
11284  ZoomButton->Enabled = false;
11285  HomeButton->Enabled = false;
11286  NewHomeButton->Enabled = false;
11287  ScreenLeftButton->Enabled = false;
11288  ScreenRightButton->Enabled = false;
11289  ScreenUpButton->Enabled = false;
11290  ScreenDownButton->Enabled = false;
11291 */
11292  Utilities->CallLogPop(1875);
11293  }
11294  catch(const Exception &e)
11295  {
11296  ErrorLog(181, e.Message);
11297  }
11298 }
11299 
11300 // ---------------------------------------------------------------------------
11301 
11302 void __fastcall TInterface::TTClockExitButtonClick(TObject *Sender)
11303 {
11304  try
11305  {
11306  TrainController->LogEvent("TTClockExitButtonClick");
11307  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockExitButtonClick");
11308  TTClockAdjPanel->Visible = false;
11309  TTClockAdjButton->Enabled = true;
11310 /* these dealt with in ClockTimer2
11311  ZoomButton->Enabled = true;
11312  HomeButton->Enabled = true;
11313  NewHomeButton->Enabled = true;
11314  ScreenLeftButton->Enabled = true;
11315  ScreenRightButton->Enabled = true;
11316  ScreenUpButton->Enabled = true;
11317  ScreenDownButton->Enabled = true;
11318  OperatingPanel->Enabled = true;
11319  OperatingPanelLabel->Caption = "Operation";
11320 */
11321  Display->ShowWarningLog(0);
11322  double TTClockTimeChange = double(TrainController->RestartTime) - PauseEntryRestartTime;
11323  if((TTClockSpeed != PauseEntryTTClockSpeed) || (TTClockTimeChange > 0.000347))
11324  // 30 seconds, min increase is 1 minute & don't trust doubles to stay exactly equal
11325  {
11326  AnsiString Message =
11327  "Changes have been made to the timetable clock - you may wish to save a session before resuming operation.\nTo cancel all changes click 'Adjust the timetable clock' then click the reset button BEFORE resuming operation.";
11328  ShowMessage(Message);
11329  }
11330 // Utilities->Clock2Stopped = false; // as above
11331  LastNonCtrlOrShiftKeyDown = -1; //to restore the ability to reselect T after adj panel hidden (FormKeyUp doesn't work because the Interface form doesn't have focus)
11332  Utilities->CallLogPop(1876);
11333  }
11334  catch(const Exception &e)
11335  {
11336  ErrorLog(182, e.Message);
11337  }
11338 }
11339 // ---------------------------------------------------------------------------
11340 
11341 void __fastcall TInterface::TTClockx2ButtonClick(TObject *Sender)
11342 {
11343  try
11344  {
11345  TrainController->LogEvent("TTClockx2ButtonClick");
11346  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx2ButtonClick");
11347  TTClockSpeed = 2;
11348  TTClockSpeedLabel->Caption = "x2";
11350  Utilities->CallLogPop(1878);
11351  }
11352  catch(const Exception &e)
11353  {
11354  ErrorLog(184, e.Message);
11355  }
11356 }
11357 
11358 // ---------------------------------------------------------------------------
11359 
11360 void __fastcall TInterface::TTClockx4ButtonClick(TObject *Sender)
11361 {
11362  try
11363  {
11364  TrainController->LogEvent("TTClockx4ButtonClick");
11365  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx4ButtonClick");
11366  TTClockSpeed = 4;
11367  TTClockSpeedLabel->Caption = "x4";
11369  Utilities->CallLogPop(1883);
11370  }
11371  catch(const Exception &e)
11372  {
11373  ErrorLog(189, e.Message);
11374  }
11375 }
11376 
11377 // ---------------------------------------------------------------------------
11378 
11379 void __fastcall TInterface::TTClockx8ButtonClick(TObject *Sender)
11380 {
11381  try
11382  {
11383  TrainController->LogEvent("TTClockx8ButtonClick");
11384  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx8ButtonClick");
11385  TTClockSpeed = 8;
11386  TTClockSpeedLabel->Caption = "x8";
11388  Utilities->CallLogPop(1884);
11389  }
11390  catch(const Exception &e)
11391  {
11392  ErrorLog(190, e.Message);
11393  }
11394 }
11395 
11396 // ---------------------------------------------------------------------------
11397 
11398 void __fastcall TInterface::TTClockx16ButtonClick(TObject *Sender)
11399 {
11400  try
11401  {
11402  TrainController->LogEvent("TTClockx16ButtonClick");
11403  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx16ButtonClick");
11404  TTClockSpeed = 16;
11405  TTClockSpeedLabel->Caption = "x16";
11407  Utilities->CallLogPop(1885);
11408  }
11409  catch(const Exception &e)
11410  {
11411  ErrorLog(191, e.Message);
11412  }
11413 }
11414 
11415 // ---------------------------------------------------------------------------
11416 
11417 void __fastcall TInterface::TTClockx1ButtonClick(TObject *Sender)
11418 {
11419  try
11420  {
11421  TrainController->LogEvent("TTClockx1ButtonClick");
11422  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx1ButtonClick");
11423  TTClockSpeed = 1;
11424  TTClockSpeedLabel->Caption = "x1";
11426  Utilities->CallLogPop(1886);
11427  }
11428  catch(const Exception &e)
11429  {
11430  ErrorLog(192, e.Message);
11431  }
11432 }
11433 
11434 // ---------------------------------------------------------------------------
11435 
11436 void __fastcall TInterface::TTClockxHalfButtonClick(TObject *Sender)
11437 {
11438  try
11439  {
11440  TrainController->LogEvent("TTClockxHalfButtonClick");
11441  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxHalfButtonClick");
11442  TTClockSpeed = 0.5;
11443  TTClockSpeedLabel->Caption = "x1/2";
11445  Utilities->CallLogPop(1887);
11446  }
11447  catch(const Exception &e)
11448  {
11449  ErrorLog(193, e.Message);
11450  }
11451 }
11452 
11453 // ---------------------------------------------------------------------------
11454 
11455 void __fastcall TInterface::TTClockxQuarterButtonClick(TObject *Sender)
11456 {
11457  try
11458  {
11459  TrainController->LogEvent("TTClockxQuarterButtonClick");
11460  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxQuarterButtonClick");
11461  TTClockSpeed = 0.25;
11462  TTClockSpeedLabel->Caption = "x1/4";
11464  Utilities->CallLogPop(1888);
11465  }
11466  catch(const Exception &e)
11467  {
11468  ErrorLog(194, e.Message);
11469  }
11470 }
11471 
11472 // ---------------------------------------------------------------------------
11473 
11474 void __fastcall TInterface::TTClockxEighthButtonClick(TObject *Sender)
11475 { // added for v2.3.0 for very big railways
11476  try
11477  {
11478  TrainController->LogEvent("TTClockxEighthButtonClick");
11479  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxEighthButtonClick");
11480  TTClockSpeed = 0.125;
11481  TTClockSpeedLabel->Caption = "x1/8";
11483  Utilities->CallLogPop(2099);
11484  }
11485  catch(const Exception &e)
11486  {
11487  ErrorLog(203, e.Message);
11488  }
11489 }
11490 // ---------------------------------------------------------------------------
11491 
11492 void __fastcall TInterface::TTClockxSixteenthButtonClick(TObject *Sender)
11493 { // added for v2.3.0 for very big railways
11494  try
11495  {
11496  TrainController->LogEvent("TTClockxSixteenthButtonClick");
11497  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxSixteenthButtonClick");
11498  TTClockSpeed = 0.0625;
11499  TTClockSpeedLabel->Caption = "x1/16";
11501  Utilities->CallLogPop(2100);
11502  }
11503  catch(const Exception &e)
11504  {
11505  ErrorLog(204, e.Message);
11506  }
11507 }
11508 
11509 // ---------------------------------------------------------------------------
11510 
11511 void __fastcall TInterface::TTClockAdd1hButtonClick(TObject *Sender)
11512 {
11513  try
11514  {
11515  TrainController->LogEvent("TTClockAdd1hButtonClick");
11516  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd1hButtonClick");
11517  double TTClockIncrement = 1.0 / 24;
11518  TrainController->RestartTime += TDateTime(TTClockIncrement);
11521  Utilities->CallLogPop(1879);
11522  }
11523  catch(const Exception &e)
11524  {
11525  ErrorLog(185, e.Message);
11526  }
11527 }
11528 
11529 // ---------------------------------------------------------------------------
11530 
11531 void __fastcall TInterface::TTClockAdd10mButtonClick(TObject *Sender)
11532 {
11533  try
11534  {
11535  TrainController->LogEvent("TTClockAdd10mButtonClick");
11536  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd10mButtonClick");
11537  double TTClockIncrement = 1.0 / 144;
11538  TrainController->RestartTime += TDateTime(TTClockIncrement);
11541  Utilities->CallLogPop(1881);
11542  }
11543  catch(const Exception &e)
11544  {
11545  ErrorLog(187, e.Message);
11546  }
11547 }
11548 
11549 // ---------------------------------------------------------------------------
11550 
11551 void __fastcall TInterface::TTClockAdd1mButtonClick(TObject *Sender)
11552 {
11553  try
11554  {
11555  TrainController->LogEvent("TTClockAdd1mButtonClick");
11556  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd1mButtonClick");
11557  double TTClockIncrement = 1.0 / 1440;
11558  TrainController->RestartTime += TDateTime(TTClockIncrement);
11561  Utilities->CallLogPop(1882);
11562  }
11563  catch(const Exception &e)
11564  {
11565  ErrorLog(188, e.Message);
11566  }
11567 }
11568 
11569 // ---------------------------------------------------------------------------
11570 
11571 void __fastcall TInterface::TTClockResetButtonClick(TObject *Sender)
11572 {
11573  try
11574  {
11575  TrainController->LogEvent("TTClockResetButtonClick");
11576  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockResetButtonClick");
11581  if(TTClockSpeed == 2)
11582  TTClockSpeedLabel->Caption = "x2";
11583  else if(TTClockSpeed == 4)
11584  TTClockSpeedLabel->Caption = "x4";
11585  else if(TTClockSpeed == 8)
11586  TTClockSpeedLabel->Caption = "x8";
11587  else if(TTClockSpeed == 16)
11588  TTClockSpeedLabel->Caption = "x16";
11589  else if(TTClockSpeed == 0.5)
11590  TTClockSpeedLabel->Caption = "x1/2";
11591  else if(TTClockSpeed == 0.25)
11592  TTClockSpeedLabel->Caption = "x1/4";
11593  else if(TTClockSpeed == 0.125)
11594  TTClockSpeedLabel->Caption = "x1/8";
11595  else if(TTClockSpeed == 0.0625)
11596  TTClockSpeedLabel->Caption = "x1/16";
11597  else
11598  {
11599  TTClockSpeed = 1;
11600  TTClockSpeedLabel->Caption = "x1";
11601  }
11602  Utilities->CallLogPop(1880);
11603  }
11604  catch(const Exception &e)
11605  {
11606  ErrorLog(186, e.Message);
11607  }
11608 }
11609 
11610 // ---------------------------------------------------------------------------
11611 
11612 void __fastcall TInterface::PresetAutoSigRoutesButtonClick(TObject *Sender)
11613 {
11614  try
11615  {
11616  TrainController->LogEvent("PresetAutoSigRoutesButtonClick");
11617  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PresetAutoSigRoutesButtonClick");
11618  InfoPanel->Caption = "PRE-START: Presetting automatic signal routes";
11619  OperatingPanelLabel->Caption = "Disabled";
11620  OperatingPanel->Enabled = false; // becomes re-enabled during the call to ClockTimer2
11621  ZoomButton->Enabled = false;
11622  HomeButton->Enabled = false;
11623  NewHomeButton->Enabled = false;
11624  ScreenLeftButton->Enabled = false;
11625  ScreenRightButton->Enabled = false;
11626  ScreenUpButton->Enabled = false;
11627  ScreenDownButton->Enabled = false;
11628 
11629  Screen->Cursor = TCursor(-11); // Hourglass
11630  TPrefDirElement StartElement, EndElement;
11631  bool PointsChanged, AtLeastOneSet = false;
11632  int LastIteratorValue = 0;
11633  while(true)
11634  {
11635  if(!EveryPrefDir->GetStartAndEndPrefDirElements(0, StartElement, EndElement, LastIteratorValue))
11636  break;
11637  // rest of routine here - i.e. build the routes
11638  ConstructRoute->ClearRoute(); // in case not empty though should be
11639  AtLeastOneSet = true;
11640  if(ConstructRoute->GetPreferredRouteStartElement(1, StartElement.HLoc, StartElement.VLoc, EveryPrefDir, true, true))
11641  // true for both ConsecSignalsRoute & AutoSigsFlag
11642  {}
11643  if(ConstructRoute->GetNextPreferredRouteElement(1, EndElement.HLoc, EndElement.VLoc, EveryPrefDir, true, true, ConstructRoute->ReqPosRouteID,
11644  PointsChanged))
11645  {}
11647  }
11648  if(AtLeastOneSet)
11649  {
11652  }
11653  else
11654  {
11655  ShowMessage("No presettable automatic signal routes are available");
11656  }
11657  Screen->Cursor = TCursor(-2); // Arrow
11658  Utilities->CallLogPop(1994);
11659  }
11660  catch(const Exception &e)
11661  {
11662  ErrorLog(195, e.Message);
11663  }
11664 }
11665 
11666 // ---------------------------------------------------------------------------
11667 
11668 void __fastcall TInterface::FormResize(TObject *Sender) // new at v2.1.0
11669 {
11670  try
11671  {
11672  if(!SkipFormResizeEvent) // to avoid calling during startup and especially during shutdown
11673  { // else fails on shutdown because HiddenScreen & other things no longer exist
11674  int DispW = (Interface->Width - 64 - 16) / 16;
11675 // will truncate down to a multiple of 16 (64 = side panels and 16 compensates for excess width of Interface)
11676  int DispH = (Interface->Height - 192) / 16;
11677  MainScreen->Width = DispW * 16;
11678  MainScreen->Height = DispH * 16;
11679  Utilities->ScreenElementWidth = DispW;
11680  Utilities->ScreenElementHeight = DispH;
11681  HiddenScreen->Width = MainScreen->Width;
11682  HiddenScreen->Height = MainScreen->Height;
11683  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
11684  PerformancePanel->Left = MainScreen->Left;
11685  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height; // new at v2.2.0
11686  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width;
11687  SigImagePanel->Left = (Interface->Width - SigImagePanel->Width) / 2; // added for v2.3.0
11688  DevelopmentPanel->Top = MainScreen->Top + MainScreen->Height - DevelopmentPanel->Height; // new v2.2.0
11689  DevelopmentPanel->Left = MainScreen->Left + MainScreen->Width - DevelopmentPanel->Width; // new v2.2.0
11690  MTBFEditBox->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 32; // new v2.4.0 32 is to place it above the positional panel
11691  MTBFLabel->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30 - 55; // new v2.4.0 placed above and to the left of MTBFEditBox
11692  PositionalPanel->Left = MainScreen->Left + MainScreen->Width; // changed at v2.4.0
11693  PositionalPanel->Top = MainScreen->Top; // changed at v2.4.0
11694  PositionalPanel->Height = MainScreen->Height; // changed at v2.4.0
11695 
11696  if(!Display->ZoomOutFlag)
11697  {
11699  }
11700  else
11701  {
11702  Display->ClearDisplay(11);
11704  }
11705  Display->Update();
11706  }
11707  }
11708  catch(const Exception &e)
11709  {
11710  ErrorLog(197, e.Message);
11711  }
11712 }
11713 
11714 // ---------------------------------------------------------------------------
11715 
11716 void __fastcall TInterface::OperatorActionButtonClick(TObject *Sender)
11717 {
11718  try
11719  {
11720  TrainController->LogEvent("OperatorActionButtonClick");
11721  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperatorActionButtonClick");
11723  {
11724  ShowOperatorActionPanel = true;
11725  OperatorActionPanel->Visible = true;
11727  OperatorActionButton->Glyph->LoadFromResourceName(0, "HideOpActionPanel");
11728  }
11729  else
11730  {
11731  ShowOperatorActionPanel = false;
11732  OperatorActionPanel->Visible = false;
11734  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel");
11735  }
11736  Utilities->CallLogPop(2073);
11737  }
11738  catch(const Exception &e)
11739  {
11740  ErrorLog(199, e.Message);
11741  }
11742 }
11743 
11744 // ---------------------------------------------------------------------------
11745 
11747 {
11748  try
11749  {
11750  TrainController->LogEvent("ConverttoRightHandSignalsMenuItemClick");
11751  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ConverttoRightHandSignalsMenuItemClick");
11753  if(Utilities->RHSignalFlag) // RH sigs after conversion
11754  {
11755  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Left Hand Signals";
11757  {
11759  }
11760  else
11761  {
11763  }
11764  SigImagePanel->Caption = "Signals will be on the right hand side of the track";
11765  SigsOnLeftImage1->Visible = false;
11766  SigsOnLeftImage2->Visible = false;
11767  SigsOnRightImage1->Visible = true;
11768  SigsOnRightImage2->Visible = true;
11769  std::ofstream SigFile((CurDir + "\\Signal.hnd").c_str());
11770  if(SigFile.fail())
11771  {
11772  ShowMessage("Failed to store right hand signal setting, program will default to left hand signals when next loaded");
11773  }
11774  else
11775  {
11776  Utilities->SaveFileString(SigFile, "RHSignals");
11777  }
11778  }
11779  else // LH sigs after conversion
11780  {
11781  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
11783  {
11785  }
11786  else
11787  {
11789  }
11790  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
11791  SigsOnRightImage1->Visible = false;
11792  SigsOnRightImage2->Visible = false;
11793  SigsOnLeftImage1->Visible = true;
11794  SigsOnLeftImage2->Visible = true;
11795  std::ofstream SigFile((CurDir + "\\Signal.hnd").c_str());
11796  if(SigFile.fail())
11797  {
11798  // no need for message as will default to LH: ShowMessage("Failed to store left hand signal setting, program will default to left hand signals when next loaded");
11799  }
11800  else
11801  {
11802  Utilities->SaveFileString(SigFile, "LHSignals");
11803  }
11804  }
11805  Utilities->CallLogPop(2097);
11806  }
11807  catch(const Exception &e)
11808  {
11809  ErrorLog(202, e.Message);
11810  }
11811 }
11812 // ---------------------------------------------------------------------------
11813 
11814 void __fastcall TInterface::MTBFEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11815 
11816 {
11817  try
11818  {
11819  TrainController->LogEvent("MTBFEditBoxKeyUp," + AnsiString(Key));
11820  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxKeyUp," + AnsiString(Key));
11821  if((Level1Mode != OperMode) || (Level2OperMode != PreStart))
11822  {
11823  Utilities->CallLogPop(2160);
11824  return;
11825  }
11826  bool TooBigFlag = false, BadCharsFlag = false;
11829  if(MTBFEditBox->Text.Length() > 0)
11830  {
11831  for(int x = 1; x <= MTBFEditBox->Text.Length(); x++)
11832  {
11833  if((MTBFEditBox->Text[x] < '0') || (MTBFEditBox->Text[x] > '9'))
11834  {
11835  BadCharsFlag = true;
11836  break;
11837  }
11838  }
11839  if(!BadCharsFlag)
11840  {
11841  if(StrToInt(MTBFEditBox->Text) > 10000)
11842  {
11843  TooBigFlag = true;
11844  }
11845  }
11846  if(TooBigFlag)
11847  {
11848  ShowMessage("Maximum value allowed is 10,000");
11849  MTBFEditBox->Text = "";
11852  Utilities->CallLogPop(2161);
11853  return;
11854  }
11855  if(BadCharsFlag)
11856  {
11857  ShowMessage("Value must be a whole number with no special characters");
11858  MTBFEditBox->Text = "";
11861  Utilities->CallLogPop(2162);
11862  return;
11863  }
11864  TrainController->AvHoursIntValue = StrToInt(MTBFEditBox->Text); // ok if user enters 0 as that means no failures
11866  }
11868  {
11869  MTBFEditBox->Text = "";
11871  }
11872  Utilities->CallLogPop(2163);
11873  }
11874  catch(const Exception &e)
11875  {
11876  ErrorLog(209, e.Message);
11877  }
11878 }
11879 
11880 // ---------------------------------------------------------------------------
11881 
11882 void __fastcall TInterface::MTBFEditBoxClick(TObject *Sender)
11883 {
11884  try
11885  {
11886  TrainController->LogEvent("MTBFEditBoxClick");
11887  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxClick");
11888  if((Level1Mode != OperMode) || (Level2OperMode != PreStart))
11889  {
11890  MTBFEditBox->ReadOnly = true; // it should be anyway but include here for safety
11892  "Values can only be entered or changed in Pre-Start mode\ni.e. after selecting 'Operate railway' but before clicking 'Run'");
11893  }
11894  Utilities->CallLogPop(2164);
11895  }
11896  catch(const Exception &e)
11897  {
11898  ErrorLog(210, e.Message);
11899  }
11900 }
11901 
11902 // ---------------------------------------------------------------------------
11903 
11904 void __fastcall TInterface::UserGraphicButtonClick(TObject *Sender)
11905 {
11906  try
11907  {
11908  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxClick");
11909  LengthConversionPanel->Visible = false;
11910  SpeedConversionPanel->Visible = false;
11911  DistanceKey->Visible = false;
11912  TrackElementPanel->Visible = false;
11913  SigAspectButton->Enabled = false;
11915  SetLevel2TrackMode(63);
11916  Display->Update();
11917  if(SelectedGraphicFileName != "")
11918  {
11919  UserGraphicReselectPanel->Visible = true;
11920  }
11921  else
11922  {
11923  UserGraphicReselectPanel->Visible = false;
11924  LoadUserGraphic(0);
11925  }
11926  Utilities->CallLogPop(2183);
11927  }
11928  catch(const Exception &e)
11929  {
11930  ErrorLog(212, e.Message);
11931  }
11932 }
11933 
11934 // ---------------------------------------------------------------------------
11935 
11936 void __fastcall TInterface::ReselectUserGraphicClick(TObject *Sender)
11937 {
11938  try
11939  {
11940  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ReselectUserGraphicClick");
11941  TrainController->LogEvent("ReselectUserGraphicClick " + SelectedGraphicFileName);
11942  UserGraphicReselectPanel->Visible = false;
11943  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
11944  if(UGMIt == Track->UserGraphicMap.end())
11945  {
11946  ShowMessage("Unable to find graphic file " + SelectedGraphicFileName + ". Check it still exists.");
11947  Utilities->CallLogPop(2196);
11948  return;
11949  }
11951  SetLevel2TrackMode(64);
11952  Utilities->CallLogPop(2184);
11953  }
11954  catch(const Exception &e)
11955  {
11956  ErrorLog(213, e.Message);
11957  }
11958 }
11959 // ---------------------------------------------------------------------------
11960 
11961 void __fastcall TInterface::SelectNewGraphicClick(TObject *Sender)
11962 {
11963  try
11964  {
11965  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectNewGraphicClick");
11966  UserGraphicReselectPanel->Visible = false;
11967  LoadUserGraphic(1);
11968  Utilities->CallLogPop(2185);
11969  }
11970  catch(const Exception &e)
11971  {
11972  ErrorLog(214, e.Message);
11973  }
11974 }
11975 
11976 // ---------------------------------------------------------------------------
11977 // end of fastcalls & directly associated functions
11978 // ---------------------------------------------------------------------------
11979 
11980 void TInterface::ClearandRebuildRailway(int Caller) // now uses HiddenScreen to help avoid flicker
11981 {
11982  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearandRebuildRailway");
11983  bool ClockState = Utilities->Clock2Stopped;
11984 
11985  Utilities->Clock2Stopped = true;
11987  Track->RebuildUserGraphics(0, HiddenDisplay); // new at v2.4.0, plot first so all else overwrites, including the grid if selected
11988  if(ScreenGridFlag && (Level1Mode == TrackMode))
11989  {
11990  int WidthNum = int(MainScreen->Width / 160) + 1;
11991  int HeightNum = int(MainScreen->Height / 144) + 1;
11992  for(int x = 0; x < WidthNum; x++)
11993  {
11994  for(int y = 0; y < HeightNum; y++)
11995  {
11996  HiddenDisplay->PlotAbsolute(0, x * 160, y * 144, RailGraphics->GridBitmap);
11997  }
11998  }
11999  }
12000 
12001 // TextHandler->RebuildFromTextVector(1, HiddenDisplay); This now incorporated in RebuildTrackAndText so that text is plotted after inactive
12002 // elements but before active elements. This is so text can overwite stations and non-station named locations.
12003 
12005 
12006 // Display->Output->Invalidate(); experiment, needs TDisplay Output to be public. Trying to invoke the white flashes that
12007 // used to occur frequently without Disp->Update() in PlotOriginal
12008 
12009  // OperMode LCs plotted below
12011  {
12013  }
12014 
12015  if(Level1Mode == PrefDirMode)
12016  {
12017  if(EveryPrefDir->PrefDirSize() > 0)
12018  {
12020  }
12022  {
12024  }
12025  }
12026 
12027  if(Level1Mode == TrackMode)
12028  {
12030  {
12031  LocationNameButton->Enabled = true;
12032  }
12033  else
12034  {
12035  LocationNameButton->Enabled = false;
12036  }
12037  }
12038 
12040  {
12042  DistanceKey->Visible = true;
12043  DistancesMarked = true;
12044  LengthConversionPanel->Visible = true;
12045  SpeedConversionPanel->Visible = true;
12046  }
12047 
12048  if(Level2TrackMode == DistanceContinuing) // for extended distances
12049  {
12050  if(ConstructPrefDir->PrefDirSize() > 0)
12051  {
12054  DistanceKey->Visible = true;
12055  DistancesMarked = true;
12056  LengthConversionPanel->Visible = true;
12057  SpeedConversionPanel->Visible = true;
12058  }
12059  }
12060 
12062  // this is to keep the distance markers if they are already present when Select is chosen, in case user wishes to choose SelectLengths,
12063  // don't need to display ConstructPrefDir marker as that only needed in DistanceContinuing mode
12064  {
12066  DistanceKey->Visible = true;
12067  }
12068 
12070  // cancel DistancesMarked if exit from any of these modes
12071  {
12072  DistancesMarked = false;
12073  DistanceKey->Visible = false;
12074  LengthConversionPanel->Visible = false; // added at v1.3.1 to remove when distance/speed setting exited
12075  SpeedConversionPanel->Visible = false; // added at v1.3.1 to remove when distance/speed setting exited
12076  }
12077 
12079  // in process of moving so use NewSelectBitmapHLoc & VLoc
12080  {
12082  }
12083 
12085  // not in process of moving or failed to click mouse within selection so use SelectBitmapHLoc & VLoc
12086  {
12088  }
12089 
12090  if(Level1Mode == OperMode)
12091  {
12093  if(!AllRoutes->LockedRouteVector.empty())
12094  {
12095  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
12096  {
12097  if(!(AllRoutes->TrackIsInARoute(7, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos)))
12098  {
12099  AllRoutes->LockedRouteVector.erase(LRVIT);
12100  // if end element not in route then a train must have entered it from the wrong end and erased the whole route,
12101  // hence no longer needed so get rid of it (end of route can't be points, crossover or bridge so danger of
12102  // route being on the other track of a 2-track element doesn't arise)
12103  continue;
12104  }
12105  TOneRoute Route = AllRoutes->GetFixedRouteAt(0, LRVIT->RouteNumber);
12106  int x = Route.PrefDirSize() - 1;
12107  bool BreakFlag = false;
12108  TPrefDirElement PrefDirElement = Route.GetFixedPrefDirElementAt(1, x);
12109  while(PrefDirElement.GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
12110  {
12111  HiddenDisplay->PlotOutput(10, (PrefDirElement.HLoc) * 16, (PrefDirElement.VLoc) * 16,
12112  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
12113  if(!(AllRoutes->TrackIsInARoute(8, PrefDirElement.Conn[PrefDirElement.GetELinkPos()],
12114  PrefDirElement.ConnLinkPos[PrefDirElement.GetELinkPos()])))
12115  {
12116  BreakFlag = true;
12117  break; // train removed earlier element from route so stop here
12118  }
12119  x--;
12120  PrefDirElement = Route.GetFixedPrefDirElementAt(2, x);
12121  }
12122  if(!BreakFlag)
12123  {
12124  if(PrefDirElement.GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
12125  {
12126  HiddenDisplay->PlotOutput(11, (PrefDirElement.HLoc) * 16, (PrefDirElement.VLoc) * 16,
12127  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
12128  }
12129  }
12130  }
12131  }
12132 
12133  if(RouteMode == RouteContinuing)
12134  {
12136 // system thinks overlay is already plotted, so plot original to reset the OverlayPlotted flag
12139  if(AutoSigsFlag)
12141  else if(ConsecSignalsRoute)
12143  else
12145  }
12146 
12147  if(Track->PointFlashFlag)
12148  {
12149  // need to reset the screen location for picking up the original graphic
12150  int Left, Top; // Embarcadero change - these missing in error from Borland file
12152  // note that the above Pos values are wrt layout, not the screen, but the Left & Top values are wrt screen
12153  PointFlash->SetSourceRect(Left, Top);
12154  PointFlash->LoadOriginalScreenGraphic(4); // reload from new position
12155  // doesn't matter whether Flash was on or off when this function called as will sort itself out later (may miss a flash but won't be noticeable)
12156  }
12157 
12158  // now plot level crossings (must be after routes). These don't need any base elements to be plotted as they are already plotted.
12159  // In order to avoid plotting the whole LC for every element of a LC a TempMarker is used
12160  for(unsigned int x = 0; x < Track->LCVector.size(); x++)
12161  {
12162  (Track->InactiveTrackVector.begin() + (*(Track->LCVector.begin() + x)))->TempMarker = false;
12163  }
12164  for(unsigned int x = 0; x < Track->LCVector.size(); x++)
12165  {
12166  int BaseSpeedTag;
12167  TTrackElement ATE;
12168  TTrackElement ITE = *(Track->InactiveTrackVector.begin() + (*(Track->LCVector.begin() + x)));
12169  {
12170  BaseSpeedTag = Track->GetTrackElementFromTrackMap(0, ITE.HLoc, ITE.VLoc).SpeedTag;
12171  if(ITE.TempMarker == false)
12172  {
12173  if(ITE.Attribute == 0)
12174  {
12176  }
12177  else if(ITE.Attribute == 1)
12178  {
12180  }
12181  // if ITE->Attribute == 2 then LC is changing, FlashingGraphics will take care of flashing & final plotting
12182  // won't set marker but no real time lost in this case
12183  }
12184  }}
12186  }
12187 
12188  Display->ZoomOutFlag = false;
12189  ZoomButton->Glyph->LoadFromResourceName(0, "ZoomOut");
12190  MainScreen->Picture->Bitmap->Assign(HiddenScreen->Picture->Bitmap);
12191  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
12192  Utilities->Clock2Stopped = ClockState;
12193  Utilities->CallLogPop(91);
12194 }
12195 
12196 // ---------------------------------------------------------------------------
12197 
12198 bool TInterface::HighLightOneGap(int Caller, int &HLoc, int &VLoc)
12199 {
12200  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",HighLightOneGap");
12201  if(Track->FindAndHighlightAnUnsetGap(1)) // true if find one
12202  {
12203  if(!PreventGapOffsetResetting) // don't reset display position if returning from zoomout mode
12204  {
12205  while((Display->DisplayOffsetH - Track->GetGapHLoc()) > 0)
12206  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
12209  while((Display->DisplayOffsetV - Track->GetGapVLoc()) > 0)
12210  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
12213  }
12214  InfoPanel->Visible = true;
12215  InfoPanel->Caption = "CONNECTING GAPS: Click on connecting element";
12216  ClearandRebuildRailway(31); // get rid of earlier gap selection
12217  Utilities->CallLogPop(92);
12218  return true; // return as one now identified & over to MainScreenMouseDown with Level2TrackMode = GapSetting
12219  }
12220  Utilities->CallLogPop(93);
12221  return false; // no unset ones left to find
12222 }
12223 
12224 // ---------------------------------------------------------------------------
12225 
12227 {
12228  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearEverything");
12229  if(FileChangedFlag)
12230  {
12231  UnicodeString MessageStr = "The railway has changed, close it without saving?";
12232  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
12233  if(button == IDNO)
12234  {
12235  Utilities->CallLogPop(1140);
12236  return false;
12237  }
12238  }
12239  Display->ClearDisplay(7);
12241 
12242  Display->DisplayOffsetH = 0;
12243  Display->DisplayOffsetV = 0;
12248 
12249 // these ensure that all persistent vectors, maps & multimaps etc are cleared
12250  delete TrainController;
12251  delete EveryPrefDir;
12252  delete ConstructRoute;
12253  delete ConstructPrefDir;
12254  delete AllRoutes;
12255  delete Track;
12256  delete TextHandler;
12257 // NB can't delete & recreate Utilities or will lose the CallLog file & have errors due to log being empty when try to
12258 // pop earlier pushed values
12259 // OK though as no containers in Utilities that need to clear & PerformanceFile recreated when begin to operate a later
12260 // railway
12261  TextHandler = new TTextHandler;
12262  Track = new TTrack;
12263  AllRoutes = new TAllRoutes;
12265  ConstructRoute = new TOneRoute;
12266  EveryPrefDir = new TOnePrefDir;
12268  PerformanceLogBox->Lines->Clear();
12269  ResetAll(1);
12270  Utilities->CallLogPop(94);
12271  return true;
12272 }
12273 
12274 // ---------------------------------------------------------------------------
12275 
12276 bool TInterface::FileIntegrityCheck(int Caller, char *FileName) const // true for success
12277 {
12278  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FileIntegrityCheck," + AnsiString(FileName));
12279  std::ifstream VecFile(FileName);
12280 
12281  if(VecFile.is_open())
12282  {
12283  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // Program version
12284  {
12285  VecFile.close();
12286  Utilities->CallLogPop(1805);
12287  return false;
12288  }
12289  if(!Utilities->CheckFileInt(VecFile, -1000000, 1000000)) // DisplayOffsetHHome
12290  {
12291  VecFile.close();
12292  Utilities->CallLogPop(1440);
12293  return false;
12294  }
12295  if(!Utilities->CheckFileInt(VecFile, -1000000, 1000000)) // DisplayOffsetVHome
12296  {
12297  VecFile.close();
12298  Utilities->CallLogPop(1441);
12299  return false;
12300  }
12301  bool GraphicsFollow = false;
12302  int NumberOfActiveElements;
12303  if(!(Track->CheckTrackElementsInFile(1, NumberOfActiveElements, GraphicsFollow, VecFile))) // for new loads
12304  {
12305  VecFile.close();
12306  Utilities->CallLogPop(95);
12307  return false;
12308  }
12309  if(!(TextHandler->CheckTextElementsInFile(0, VecFile)))
12310  {
12311  VecFile.close();
12312  Utilities->CallLogPop(96);
12313  return false;
12314  }
12315  if(!(EveryPrefDir->CheckOnePrefDir(0, NumberOfActiveElements, VecFile)))
12316  {
12317  VecFile.close();
12318  Utilities->CallLogPop(97);
12319  return false;
12320  }
12321  if(GraphicsFollow)
12322  {
12323  if(!Track->CheckUserGraphics(0, VecFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
12324  {
12325  VecFile.close();
12326  Utilities->CallLogPop(2186);
12327  return false;
12328  }
12329  }
12330  VecFile.close();
12331  }
12332  else
12333  {
12334  Utilities->CallLogPop(1153);
12335  return false;
12336  }
12337  Utilities->CallLogPop(98);
12338  return true;
12339 }
12340 
12341 // ---------------------------------------------------------------------------
12342 
12343 void TInterface::Delay(int Caller, double Msec)
12344 {
12345  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Delay," + AnsiString(Msec));
12346  TDateTime First, Second;
12347  bool Finished = false;
12348 
12349  First = TDateTime::CurrentDateTime();
12350  double TimeVal1 = 86400000 * double(First); // no of msec in a day
12351 
12352  while(!Finished)
12353  {
12354  Second = TDateTime::CurrentDateTime();
12355  double TimeVal2 = 86400000 * double(Second);
12356  if((TimeVal2 - TimeVal1) > Msec)
12357  Finished = true;
12358  }
12359  Utilities->CallLogPop(1203);
12360 }
12361 
12362 // ---------------------------------------------------------------------------
12363 
12365 {
12366  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetCurrentSpeedButton");
12367  if(CurrentSpeedButton)
12368  CurrentSpeedButton->Down = false;
12369  CurrentSpeedButton = 0;
12370  Utilities->CallLogPop(1204);
12371 }
12372 
12373 // ---------------------------------------------------------------------------
12374 
12376 {
12377  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MovingTrainPresentOnFlashingRoute");
12378  int TrainID;
12379 
12380  if(ConstructRoute->SearchVectorSize() == 0)
12381  {
12382  Utilities->CallLogPop(99);
12383  return false;
12384  }
12385  for(unsigned int x = 0; x < ConstructRoute->SearchVectorSize(); x++)
12386  {
12387  TPrefDirElement PrefDirElement = ConstructRoute->GetFixedSearchElementAt(14, x);
12388  if(PrefDirElement.TrackType == Bridge)
12389  {
12390  if(PrefDirElement.GetXLinkPos() < 2)
12391  TrainID = Track->TrackElementAt(486, PrefDirElement.GetTrackVectorPosition()).TrainIDOnBridgeTrackPos01;
12392  else
12393  TrainID = Track->TrackElementAt(487, PrefDirElement.GetTrackVectorPosition()).TrainIDOnBridgeTrackPos23;
12394  }
12395  else
12396  TrainID = Track->TrackElementAt(488, PrefDirElement.GetTrackVectorPosition()).TrainIDOnElement;
12397  if((TrainID > -1) && !(TrainController->TrainVectorAtIdent(4, TrainID).Stopped()))
12398  {
12399  Utilities->CallLogPop(100);
12400  return true;
12401  }
12402  // check for crossed diagonal fouling by train added at v1.2.0
12403  int TrainID; // not used
12404  int LinkNumber1 = PrefDirElement.Link[PrefDirElement.GetELinkPos()];
12405  int LinkNumber2 = PrefDirElement.Link[PrefDirElement.GetXLinkPos()];
12406  if((LinkNumber1 == 1) || (LinkNumber1 == 3) || (LinkNumber1 == 7) || (LinkNumber1 == 9))
12407  {
12408  if(Track->DiagonalFouledByTrain(1, PrefDirElement.HLoc, PrefDirElement.VLoc, LinkNumber1, TrainID))
12409  {
12410  Utilities->CallLogPop(2037);
12411  return true;
12412  }
12413  }
12414  if((LinkNumber2 == 1) || (LinkNumber2 == 3) || (LinkNumber2 == 7) || (LinkNumber2 == 9))
12415  {
12416  if(Track->DiagonalFouledByTrain(2, PrefDirElement.HLoc, PrefDirElement.VLoc, LinkNumber2, TrainID))
12417  {
12418  Utilities->CallLogPop(2038);
12419  return true;
12420  }
12421  }
12422  }
12423  Utilities->CallLogPop(101);
12424  return false;
12425 }
12426 
12427 // ---------------------------------------------------------------------------
12428 
12430 {
12431  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RevertToOriginalRouteSelector");
12432  AutoRouteStartMarker->PlotOriginal(26, Display); // if overlay not plotted will ignore
12433  SigRouteStartMarker->PlotOriginal(27, Display); // if overlay not plotted will ignore
12434  NonSigRouteStartMarker->PlotOriginal(28, Display); // if overlay not plotted will ignore
12435  RouteCancelFlag = false;
12437  {
12438  RouteCancelButton->Enabled = true;
12439  }
12440  else
12441  {
12442  RouteCancelButton->Enabled = false;
12443  }
12446 // reset here so that a n element that has been selected and then not doesn't remain set as a single element
12447  InfoPanel->Visible = true;
12448  if(Level2OperMode != Paused)
12449  {
12450  InfoPanel->Caption = InfoCaptionStore;
12451  }
12452  Utilities->CallLogPop(102);
12453 }
12454 
12455 // ---------------------------------------------------------------------------
12456 
12457 // usermode functions below
12459 {
12460  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel1Mode");
12461  if(!Display->ZoomOutFlag)
12462  {
12465  Track->GapFlashFlag = false;
12466  }
12467 // GapFlash resets when any mode selected unless zoomed out
12468 // note that if selecting zoom back in then this will be called before ZoomOutFlag is reset so won't
12469 // reset GapFlashFlag
12470  switch(Level1Mode) // use the data member
12471  {
12472  case BaseMode:
12473  CopyMenuItem->ShortCut = TextToShortCut(""); // added these for v2.1.0 to set default values after use of the 'Edit' menu during track building
12474  CutMenuItem->ShortCut = TextToShortCut(""); // to allow normal cutting/copying/pasting, especially in timetable construction or editing
12475  PasteMenuItem->ShortCut = TextToShortCut("");
12480  LengthConversionPanel->Visible = false;
12481  SpeedConversionPanel->Visible = false;
12482  TimetableEditPanel->Visible = false;
12483  TrackBuildPanel->Visible = false;
12484  TrackElementPanel->Visible = false;
12485  LocationNameTextBox->Visible = false;
12486  TextBox->Visible = false;
12487  TrackLengthPanel->Visible = false;
12488  InfoPanel->Visible = false;
12489  PrefDirPanel->Visible = false;
12490  TimetablePanel->Visible = false;
12491  OperatingPanel->Visible = false;
12492  PrefDirKey->Visible = false;
12493  TrackLinkedImage->Visible = false;
12494  TrackNotLinkedImage->Visible = false;
12495  GapsSetImage->Visible = false;
12496  GapsNotSetImage->Visible = false;
12497  LocationNamesSetImage->Visible = false;
12498  LocationNamesNotSetImage->Visible = false;
12499  ModeMenu->Enabled = true;
12500  FileMenu->Enabled = true;
12501  EditMenu->Enabled = false;
12502  BuildTrackMenuItem->Enabled = true;
12503  SigAspectButton->Enabled = false;
12504  Track->ChangingLCVector.clear();
12505  Track->BarriersDownVector.clear();
12507  ConverttoRightHandSignalsMenuItem->Enabled = false; // new at v2.3.0
12508  SigImagePanel->Visible = false; // new at v2.3.0
12509  MTBFEditBox->Visible = false; // new at v2.4.0
12510  MTBFLabel->Visible = false;
12511  if(Track->IsTrackFinished())
12512  {
12513  PlanPrefDirsMenuItem->Enabled = true;
12514  if(TimetableTitle != "")
12515  {
12516  OperateRailwayMenuItem->Enabled = true;
12517  }
12518  else
12519  {
12520  OperateRailwayMenuItem->Enabled = false;
12521  }
12522  }
12523  else
12524  {
12525  PlanPrefDirsMenuItem->Enabled = false;
12526  OperateRailwayMenuItem->Enabled = false;
12527  }
12528  if(RlyFile)
12529  {
12530  LoadTimetableMenuItem->Enabled = true;
12531  }
12532  else
12533  {
12534  LoadTimetableMenuItem->Enabled = false;
12535  }
12536  LoadRailwayMenuItem->Enabled = true;
12537  if(NoRailway())
12538  {
12539  SaveAsMenuItem->Enabled = false;
12540  ImageMenu->Enabled = false;
12541  SaveImageAndGridMenuItem->Enabled = false;
12542  SaveImageNoGridMenuItem->Enabled = false;
12543  SaveImageAndPrefDirsMenuItem->Enabled = false;
12544  SaveOperatingImageMenuItem->Enabled = false;
12545  BlackBgndMenuItem->Enabled = false;
12546  WhiteBgndMenuItem->Enabled = false;
12547  BlueBgndMenuItem->Enabled = false;
12548  ConverttoRightHandSignalsMenuItem->Enabled = true; // new at v2.3.0
12549  SigImagePanel->Visible = true; // new at v2.3.0
12550  if(Utilities->clTransparent != TColor(0))
12551  {
12552  BlackBgndMenuItem->Enabled = true;
12553  }
12554  if(Utilities->clTransparent != TColor(0xFFFFFF))
12555  {
12556  WhiteBgndMenuItem->Enabled = true;
12557  }
12558  if(Utilities->clTransparent != TColor(0x330000))
12559  {
12560  BlueBgndMenuItem->Enabled = true;
12561  }
12562  ClearAllMenuItem->Enabled = false;
12563  InfoPanel->Visible = true;
12564  InfoPanel->Caption = "Select an option from the File, Mode or Help menus";
12565  }
12566  else
12567  {
12568  InfoPanel->Visible = false;
12569  SaveAsMenuItem->Enabled = true;
12570  ImageMenu->Enabled = true;
12571  SaveImageAndGridMenuItem->Enabled = true;
12572  SaveImageNoGridMenuItem->Enabled = true;
12573  if(EveryPrefDir->PrefDirSize() > 0)
12574  SaveImageAndPrefDirsMenuItem->Enabled = true;
12575  else
12576  SaveImageAndPrefDirsMenuItem->Enabled = false;
12577  BlackBgndMenuItem->Enabled = false;
12578  WhiteBgndMenuItem->Enabled = false;
12579  BlueBgndMenuItem->Enabled = false;
12580  SaveOperatingImageMenuItem->Enabled = false;
12581  ClearAllMenuItem->Enabled = true;
12582  }
12583  if(SavedFileName == "")
12584  {
12585  SaveMenuItem->Enabled = false;
12586  }
12587  else if(!FileChangedFlag)
12588  {
12589  SaveMenuItem->Enabled = false;
12590  }
12591  else if((SavedFileName[SavedFileName.Length()] == 'y') || (SavedFileName[SavedFileName.Length()] == 'Y')) // 'rly' file
12592  {
12593  if(!(Track->IsReadyForOperation()))
12594  {
12595  SaveMenuItem->Enabled = false; // can't save under its old name as not now a .rly file
12596  }
12597  else
12598  {
12599  SaveMenuItem->Enabled = true; // must have changed some of the PrefDirs (because FileChangedFlag is true)
12600  }
12601  }
12602  else
12603  SaveMenuItem->Enabled = true;
12604  LoadSessionMenuItem->Enabled = true;
12605  ExitMenuItem->Enabled = true;
12606  ScreenGridFlag = false;
12607  TrainController->CrashWarning = false;
12608  TrainController->DerailWarning = false;
12609  TrainController->SPADWarning = false;
12611  TrainController->CallOnWarning = false;
12614  UserGraphicReselectPanel->Visible = false;
12615  ClearandRebuildRailway(32); // to get rid of unwanted displays (eg distance markers)
12616  SetTrackBuildImages(13);
12617  break;
12618 
12619  case TimetableMode:
12623  ModeMenu->Enabled = false;
12624  SigImagePanel->Visible = false; // new at v2.3.0
12625  FileMenu->Enabled = false;
12626  EditMenu->Enabled = false;
12627  FloatingInfoMenu->Enabled = false;
12628  ImageMenu->Enabled = false;
12629  TimetableEditPanel->BringToFront();
12630  TimetableHandler();
12631  break;
12632 
12633  case TrackMode:
12634  if(Level2TrackMode == CutMoving)
12635  {
12636  Level2TrackMode = Pasting; // paste the selection
12637  SetLevel2TrackMode(52);
12638  }
12643  TrackBuildPanel->Visible = true;
12644  TrackBuildPanelLabel->Caption = "Build/modify";
12645  TrackElementPanel->Visible = false;
12646  TrackLengthPanel->Visible = false;
12647  PrefDirPanel->Visible = false;
12648  TimetablePanel->Visible = false;
12649  OperatingPanel->Visible = false;
12650  InfoPanel->Visible = false;
12651  InfoPanel->Caption = "";
12652  LocationNameTextBox->Visible = false;
12653  TextBox->Visible = false;
12654  ModeMenu->Enabled = false;
12655  SigImagePanel->Visible = false; // new at v2.3.0
12656  FileMenu->Enabled = false;
12657  // set edit menu items
12659  // track buttons
12660  AddTrackButton->Enabled = true;
12662  {
12663  LocationNameButton->Enabled = true;
12664  }
12665  else
12666  {
12667  LocationNameButton->Enabled = false;
12668  }
12669  ScreenGridButton->Enabled = true;
12670  ExitTrackButton->Enabled = true;
12671  SetGapsButton->Enabled = false;
12672  TrackOKButton->Enabled = false;
12673  if(Track->GapsUnset(5))
12674  {
12675  SetGapsButton->Enabled = true;
12676  }
12677  // only enable if there are gaps still to be set (returns false for no track)
12678  else
12679  {
12680  if(!(Track->NoActiveTrack(2)) && !(Track->IsTrackFinished()))
12681  {
12682  TrackOKButton->Enabled = true;
12683  }
12684  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
12685  }
12686  SetLengthsButton->Enabled = false;
12687  if(Track->IsTrackFinished()) // can only set lengths for several elements together if TrackFinished
12688  {
12689  SetLengthsButton->Enabled = true;
12690  }
12691  // text buttons
12692  AddTextButton->Enabled = true;
12693  TextOrUserGraphicGridButton->Enabled = true;
12694  FontButton->Enabled = true;
12695  MoveTextOrGraphicButton->Enabled = false;
12696  if(TextHandler->TextVectorSize(9) > 0)
12697  {
12698  MoveTextOrGraphicButton->Enabled = true;
12699  }
12700  if(!Track->UserGraphicVector.empty())
12701  {
12702  MoveTextOrGraphicButton->Enabled = true;
12703  }
12704  SelectionValid = false;
12706  TimetableTitle = "";
12707  SetCaption(0);
12708  break;
12709 
12710  case PrefDirMode:
12714  PrefDirPanel->Visible = true;
12715  PrefDirPanelLabel->Caption = "Preferred direction selection";
12716 
12717  InfoPanel->Visible = true;
12718  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Select preferred direction start location (right click to erase)";
12719  PrefDirKey->Visible = true;
12720  ModeMenu->Enabled = false;
12721  SigImagePanel->Visible = false; // new at v2.3.0
12722  FileMenu->Enabled = false;
12723 // set edit menu items
12725  AddPrefDirButton->Enabled = false;
12726  DeleteOnePrefDirButton->Enabled = false;
12728  if(EveryPrefDir->PrefDirSize() > 0)
12729  {
12730  DeleteAllPrefDirButton->Visible = true;
12731  DeleteAllPrefDirButton->Enabled = true;
12732  SaveImageAndPrefDirsMenuItem->Enabled = true;
12733  }
12734  else
12735  {
12736  DeleteAllPrefDirButton->Enabled = false;
12737  SaveImageAndPrefDirsMenuItem->Enabled = false;
12738  }
12739  ExitPrefDirButton->Enabled = true;
12740  ClearandRebuildRailway(33); // to mark PrefDirs & clear earlier PrefDir markers
12741 // TimetableTitle = ""; no need to unload timetable if only PrefDirs being changed
12742 // SetCaption();
12743  break;
12744 
12745  case OperMode: // if there are any PrefDirs, set to SigPref, else to NoSigNonPref; start in Paused mode
12749  OperatingPanel->Visible = true;
12750  OperatingPanelLabel->Caption = "Operation";
12751 
12752  CallingOnButton->Visible = false;
12753  PresetAutoSigRoutesButton->Visible = true;
12754  PresetAutoSigRoutesButton->Enabled = true;
12755  InfoPanel->Visible = true;
12756  SigImagePanel->Visible = false; // new at v2.3.0
12757  ModeMenu->Enabled = false;
12758  FileMenu->Enabled = false;
12759  EditMenu->Enabled = false;
12760  ImageMenu->Enabled = true;
12761  SaveImageAndGridMenuItem->Enabled = true;
12762  SaveImageNoGridMenuItem->Enabled = true;
12763  if(EveryPrefDir->PrefDirSize() > 0)
12764  SaveImageAndPrefDirsMenuItem->Enabled = true;
12765  else
12766  SaveImageAndPrefDirsMenuItem->Enabled = false;
12767  SaveOperatingImageMenuItem->Enabled = true;
12768  AutoSigsFlag = false;
12769  MTBFEditBox->Visible = true; // visible at pre-start whether any value set or not, so can set a value if required
12771  {
12772  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
12773  }
12774  else
12775  {
12776  MTBFEditBox->Text = "";
12777  }
12778  MTBFEditBox->ReadOnly = false; // because this is prestart mode
12779  MTBFLabel->Visible = true;
12780  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
12782  if(EveryPrefDir->PrefDirSize() > 0)
12783  {
12784  ConsecSignalsRoute = true;
12785  PreferredRoute = true;
12786  }
12787  else // no PrefDirs
12788  {
12789  ConsecSignalsRoute = false;
12790  PreferredRoute = false;
12791  }
12792 
12793  OperateButton->Enabled = true;
12794  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
12795  ExitOperationButton->Enabled = true;
12796  TTClockAdjButton->Enabled = true;
12797  ShowPerformancePanel = false;
12798  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
12799  ShowOperatorActionPanel = false; // new at v2.2.0
12800  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel"); // new v2.2.0
12801 
12803 
12804  Utilities->Clock2Stopped = false;
12808  TTClockSpeed = 1;
12809  TTClockSpeedLabel->Caption = "x1";
12811 
12812  PerformanceFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
12813  // format "16/06/2009 20:55:17"
12814  // avoid characters in filename:= / \ : * ? " < > |
12815  PerformanceFileName = CurDir + "\\" + PERFLOG_DIR_NAME + "\\Log " + PerformanceFileName + "; " + RailwayTitle + "; " + TimetableTitle + ".txt";
12816 
12817  Utilities->PerformanceFile.open(PerformanceFileName.c_str(), std::ios_base::out);
12818  if(Utilities->PerformanceFile.fail())
12819  {
12820  ShowMessage("Performance logfile failed to open, logs won't be saved. Ensure that there is a folder named " + PERFLOG_DIR_NAME +
12821  " in the folder where the 'Railway.exe' program file resides");
12822  }
12824 // DisableRouteButtons(2); enable route setting or pre-start
12825 // DisablePanelsStoreMainMenuStates();
12826  TrainController->ContinuationAutoSigVector.clear(); // for restarting after earlier run
12827  AllRoutes->LockedRouteVector.clear(); // for restarting after earlier run
12828 // TrainController->Operate(1);//plot trains that are present at TT start time, ready for running - no, allow route plotting prior to train entries
12829 
12830 // reset all performance indicators
12854 
12855  TrainController->OpActionPanelHintDelayCounter = 0; // new at v2.2.0 to reset hint delay
12856  OAListBox->Clear();
12857  OAListBox->Items->Add(L""); // hints for OpActionPanel
12858  OAListBox->Items->Add(L"");
12859  OAListBox->Items->Add(L"");
12860  OAListBox->Items->Add(L"Left click");
12861  OAListBox->Items->Add(L"headcode");
12862  OAListBox->Items->Add(L"to locate train");
12863  OAListBox->Items->Add(L"");
12864  OAListBox->Items->Add(L"");
12865  OAListBox->Items->Add(L"");
12866  OAListBox->Items->Add(L"");
12867  OAListBox->Items->Add(L"Left click and");
12868  OAListBox->Items->Add(L"hold grey area");
12869  OAListBox->Items->Add(L"to move panel");
12870 
12871  ClearandRebuildRailway(55); // so points display with one fillet
12872  break;
12873 
12874  case RestartSessionOperMode: // restart in Paused mode after a session load, sets both Level1Mode & Level2OperMode
12875  Level1Mode = OperMode;
12876 // Level2OperMode = Paused; this is now loaded during LoadInterface & could be PreStart of Paused
12879  OperatingPanel->Visible = true;
12880  OperatingPanelLabel->Caption = "Operation";
12881 
12882  CallingOnButton->Visible = true;
12883  PresetAutoSigRoutesButton->Visible = false;
12884  InfoPanel->Visible = true;
12885  ModeMenu->Enabled = false;
12886  SigImagePanel->Visible = false; // new at v2.3.0
12887  FileMenu->Enabled = false;
12888  EditMenu->Enabled = false;
12889  ImageMenu->Enabled = true;
12890  SaveImageAndGridMenuItem->Enabled = true;
12891  SaveImageNoGridMenuItem->Enabled = true;
12892  if(EveryPrefDir->PrefDirSize() > 0)
12893  SaveImageAndPrefDirsMenuItem->Enabled = true;
12894  else
12895  SaveImageAndPrefDirsMenuItem->Enabled = false;
12896  SaveOperatingImageMenuItem->Enabled = true;
12897 
12898  OperateButton->Enabled = true;
12899  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
12900  ExitOperationButton->Enabled = true;
12901  TTClockAdjButton->Enabled = true;
12904  if(Level2OperMode == Paused)
12905  DisableRouteButtons(3); // could be PreStart or Paused
12909  TTClockSpeed = 1;
12910  TTClockSpeedLabel->Caption = "x1";
12912  ShowPerformancePanel = false; // added at v2.2.0
12913  ShowOperatorActionPanel = false; // new at v2.2.0
12914  TrainController->OpActionPanelHintDelayCounter = 0; // new at v2.2.0 to reset hint dela
12915  OAListBox->Clear();
12916  OAListBox->Items->Add(L""); // hints for OpActionPanel
12917  OAListBox->Items->Add(L"");
12918  OAListBox->Items->Add(L"");
12919  OAListBox->Items->Add(L"Left click");
12920  OAListBox->Items->Add(L"headcode");
12921  OAListBox->Items->Add(L"to locate train");
12922  OAListBox->Items->Add(L"");
12923  OAListBox->Items->Add(L"");
12924  OAListBox->Items->Add(L"");
12925  OAListBox->Items->Add(L"");
12926  OAListBox->Items->Add(L"Left click and");
12927  OAListBox->Items->Add(L"hold grey area");
12928  OAListBox->Items->Add(L"to move panel");
12929  if((TrainController->AvHoursIntValue > 0) || (Level2OperMode == PreStart)) // only visible if already set or if still in prestart mode
12930  {
12931  MTBFEditBox->Visible = true;
12933  {
12934  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
12935  }
12936  else
12937  {
12938  MTBFEditBox->Text = "";
12939  }
12940  MTBFEditBox->ReadOnly = false; // because this is still prestart mode
12941  MTBFLabel->Visible = true;
12942  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
12944  }
12945  else
12946  {
12947  MTBFEditBox->Visible = false;
12948  MTBFEditBox->Text = "";
12949  MTBFEditBox->ReadOnly = true; // because this is not prestart mode
12950  MTBFLabel->Visible = false;
12951  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
12953  }
12954  break;
12955 
12956  default:
12957  // No further recursion in BaseMode so OK
12958  Level1Mode = BaseMode;
12959  SetLevel1Mode(29);
12960  break;
12961  }
12962  Utilities->CallLogPop(103);
12963 }
12964 
12965 // ---------------------------------------------------------------------------
12966 
12968 {
12969  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2TrackMode");
12970  if(Level1Mode != TrackMode)
12971  {
12972  // No further recursion in BaseMode so OK
12973  Level1Mode = BaseMode;
12974  SetLevel1Mode(20);
12975  Utilities->CallLogPop(1115);
12976  return;
12977  }
12979  {
12980  Utilities->CallLogPop(104);
12981  return;
12982  }
12983  switch(Level2TrackMode) // use the data member
12984  {
12985  case AddTrack:
12987  InfoPanel->Visible = true;
12988  InfoPanel->Caption = "ADDING TRACK: Select element then left click to add it. Right click an element to remove it.";
12989  LengthConversionPanel->Visible = false; // in case had been in distance setting mode
12990  SpeedConversionPanel->Visible = false; // in case had been in distance setting mode
12991  TrackElementPanel->Visible = true;
12992  TrackElementPanel->Enabled = true;
12993  SigAspectButton->Visible = true;
12994  SigAspectButton->Enabled = true;
12995  ClearandRebuildRailway(34); // to replot grid if required & clear any other unwanted items
12997  SetLengthsButton->Enabled = false;
12998  if(Track->IsTrackFinished()) // can only set lengths for several elements together if TrackFinished
12999  {
13000  SetLengthsButton->Enabled = true;
13001  }
13002  UserGraphicReselectPanel->Visible = false;
13003  SelectLengthsFlag = false; // in case still set though probably won't be
13004  break;
13005 
13006  case AddGraphic:
13007  InfoPanel->Visible = true;
13008  InfoPanel->Caption = "ADDING GRAPHIC: Left click layout to add SELECTED graphic, right click to remove ANY graphic.";
13009  break;
13010 
13011  case SelectGraphic:
13012  InfoPanel->Visible = true;
13013  InfoPanel->Caption = "SELECTING USER GRAPHIC: Select the graphic file then add as many as necessary to the layout.";
13014  break;
13015 
13016  case GapSetting:
13017  int HLoc, VLoc, Count;
13018  Count = Track->NumberOfGaps(0);
13019  if(div(Count, 2).rem == 1) // condition OK
13020  {
13021  ShowMessage("Can't connect, there are an odd number of gaps");
13023  SetLevel1Mode(77);
13025  // No further recursion in AddTrack so OK
13026  SetLevel2TrackMode(40);
13027  Utilities->CallLogPop(105);
13028  return;
13029  }
13030  if(!HighLightOneGap(2, HLoc, VLoc)) // condition OK
13031  // need to call this here to start gap setting process off,
13032  // called in MainScreenMouseDown hereafter. Function returns false for either a LocError (links not yet
13033  // complete) or no more gaps to be highlighted
13034  {
13035  // shouldn't reach here as later gaps covered in MainScreenMouseDown but leave & give error message
13036  ShowMessage("Error - Even number of gaps but all set after first call to HighLightOneGap");
13038  SetLevel1Mode(78);
13040  // No further recursion in AddTrack so OK
13041  SetLevel2TrackMode(41);
13042  Utilities->CallLogPop(106);
13043  return; // all gaps set
13044  }
13045  InfoPanel->Visible = true;
13046  InfoPanel->Caption = "CONNECTING GAPS: Click on connecting gap";
13047  UserGraphicReselectPanel->Visible = false;
13049  break;
13050 
13051  case AddText:
13052  InfoPanel->Visible = true;
13053  InfoPanel->Caption = "ADDING/EDITING TEXT: Left click to add, left click first letter to edit (+CR), or remove (+Esc)";
13054  if(TextHandler->TextVectorSize(13) > 0)
13055  {
13056  MoveTextOrGraphicButton->Enabled = true;
13057  }
13058  else
13059  {
13060  MoveTextOrGraphicButton->Enabled = false;
13061  }
13062  UserGraphicReselectPanel->Visible = false;
13063  ClearandRebuildRailway(58); // to drop DistanceKey if was displayed
13064  break;
13065 
13066  case MoveTextOrGraphic:
13067  InfoPanel->Visible = true;
13068  InfoPanel->Caption = "MOVING TEXT OR GRAPHIC: If text left click first letter, if graphic left click anywhere, then drag";
13069  UserGraphicReselectPanel->Visible = false;
13070  ClearandRebuildRailway(59); // to drop DistanceKey if was displayed
13071  break;
13072 
13073  case AddLocationName:
13074  InfoPanel->Visible = true;
13075  InfoPanel->Caption = "NAMING LOCATIONS: Click on location element to add or change name";
13076  ClearandRebuildRailway(35); // to get rid of earlier red rectangle
13077  UserGraphicReselectPanel->Visible = false;
13078  SetTrackBuildImages(12);
13079  break;
13080 
13081  case DistanceStart:
13082  InfoPanel->Visible = true;
13083  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Select first location (only non-default elements marked)";
13084  DistanceKey->Visible = true;
13085  LengthConversionPanel->Visible = true;
13086  SpeedConversionPanel->Visible = true;
13087  UserGraphicReselectPanel->Visible = false;
13088  ClearandRebuildRailway(36); // to get rid of earlier unwanted markings
13089  break;
13090 
13091  case DistanceContinuing:
13092  InfoPanel->Visible = true;
13093  if(ConstructPrefDir->PrefDirSize() == 1)
13094  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Select next location";
13095  else
13096  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
13097  UserGraphicReselectPanel->Visible = false;
13098  ClearandRebuildRailway(54); // to remove earlier end marker if present
13099  break;
13100 
13101  case TrackSelecting:
13102  Track->CopyFlag = false;
13103  if(!SelectionValid)
13104  ResetSelectRect(); // so a viewpoint change before a new SelectRect chosen doesn't redisplay
13105  // the old SelectRect (only called when entered from SelectMenuItemClick, & not from
13106  // ReselectMenuItemClick)
13107  InfoPanel->Visible = true;
13108  InfoPanel->Caption = "SELECTING: Select area - click left mouse && drag";
13109  SelectMenuItem->Enabled = false;
13110  ReselectMenuItem->Enabled = false;
13111  CancelSelectionMenuItem->Enabled = true;
13112  UserGraphicReselectPanel->Visible = false;
13113  break;
13114 
13115  case CopyMoving:
13116  Track->CopyFlag = true;
13117  InfoPanel->Visible = true;
13118  InfoPanel->Caption = "COPYING: Left click in selection && drag";
13119  CutMenuItem->Enabled = false;
13120  CopyMenuItem->Enabled = false;
13121  FlipMenuItem->Enabled = false;
13122  MirrorMenuItem->Enabled = false;
13123  RotRightMenuItem->Enabled = false;
13124  RotLeftMenuItem->Enabled = false;
13125  RotateMenuItem->Enabled = false;
13126  PasteMenuItem->Enabled = true;
13127 // PasteWithAttributesMenuItem->Enabled = false; //new at v2.2.0 - don't allow the option if copying
13128  DeleteMenuItem->Enabled = false;
13129  SelectLengthsMenuItem->Enabled = false;
13130  SelectBiDirPrefDirsMenuItem->Visible = false;
13131  CancelSelectionMenuItem->Enabled = false;
13135  UserGraphicReselectPanel->Visible = false;
13136  break;
13137 
13138  case CutMoving:
13139  { // have to use braces as otherwise the default case bypasses the initialisation of these local variables
13140  // erase track elements within selected region
13141  Track->CopyFlag = false;
13142  bool EraseSuccessfulFlag, NeedToLink = false, TextChangesMade = false, GraphicChangesMade = false; ;
13143  int ErasedTrackVectorPosition;
13144  Screen->Cursor = TCursor(-11); // Hourglass;
13145  InfoPanel->Visible = true;
13146  InfoPanel->Caption = "CUT PROCESSING: Please do not click the mouse";
13147  InfoPanel->Update();
13148  for(int H = SelectRect.left; H < SelectRect.right; H++)
13149  {
13150  for(int V = SelectRect.top; V < SelectRect.bottom; V++)
13151  {
13152  Track->EraseTrackElement(2, H, V, ErasedTrackVectorPosition, EraseSuccessfulFlag, false);
13153  if(EraseSuccessfulFlag)
13154  {
13155  if(ErasedTrackVectorPosition > -1)
13156  EveryPrefDir->RealignAfterTrackErase(1, ErasedTrackVectorPosition);
13157  NeedToLink = true;
13158  }
13159  }
13160  }
13161  // erase text elements within selected region
13162  int LowSelectHPos = SelectRect.left * 16;
13163  int HighSelectHPos = SelectRect.right * 16;
13164  int LowSelectVPos = SelectRect.top * 16;
13165  int HighSelectVPos = SelectRect.bottom * 16;
13166  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
13167  {
13168  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
13169  TextPtr--) // reverse to prevent skipping during erase
13170  {
13171  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
13172  HighSelectVPos))
13173  {
13174  if(TextHandler->TextErase(1, TextPtr->HPos, TextPtr->VPos))
13175  {;
13176  } // unused condition
13177  TextChangesMade = true;
13178  }
13179  }
13180  }
13181  // erase graphic elements that fall wholly within region to be overwritten
13182  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
13183  {
13184  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
13185  GraphicPtr--) // reverse to prevent skipping during erase
13186  {
13187  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
13188  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
13189  {
13190  Track->UserGraphicVector.erase(GraphicPtr);
13191  GraphicChangesMade = true;
13192  }
13193  }
13194  }
13195  Track->CheckMapAndTrack(11); // test
13196  Track->CheckMapAndInactiveTrack(10); // test
13197  Track->CheckLocationNameMultiMap(19); // test
13198  Screen->Cursor = TCursor(-2); // Arrow;
13199  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
13200  // if track not linked to begin with then becomes linked if NeedToLink false
13201  if(NeedToLink)
13202  Track->SetTrackFinished(false); // corrected for v2.1.0
13203  InfoPanel->Caption = "CUTTING: Left click in selection && drag";
13204  CutMenuItem->Enabled = false;
13205  CopyMenuItem->Enabled = false;
13206  FlipMenuItem->Enabled = false;
13207  MirrorMenuItem->Enabled = false;
13208  RotRightMenuItem->Enabled = false;
13209  RotLeftMenuItem->Enabled = false;
13210  RotateMenuItem->Enabled = false;
13211  PasteMenuItem->Enabled = true;
13212 // PasteWithAttributesMenuItem->Enabled = true; //new at v2.2.0 - option enabled if cutting
13213  DeleteMenuItem->Enabled = false;
13214  SelectLengthsMenuItem->Enabled = false;
13215  SelectBiDirPrefDirsMenuItem->Visible = false;
13216  CancelSelectionMenuItem->Enabled = false;
13219  if(NeedToLink || TextChangesMade || GraphicChangesMade)
13220  {
13221  ResetChangedFileDataAndCaption(20, true); // true for NonPrefDirChangesMade
13222  }
13223  ClearandRebuildRailway(37); // to overplot the erased elements with SelectBitmap
13224  UserGraphicReselectPanel->Visible = false;
13226  } break;
13227 
13228  case Pasting:
13229  { // have to use braces as otherwise the default case bypasses the initialisation of these local variables
13232  int HDiff = SelectBitmapHLoc - SelectRect.left;
13233  int VDiff = SelectBitmapVLoc - SelectRect.top;
13234  bool NeedToLink = false;
13235  bool TrackLinkingRequiredFlag;
13236  Screen->Cursor = TCursor(-11); // Hourglass;
13237  InfoPanel->Visible = true;
13238  InfoPanel->Caption = "PASTING: Please wait";
13239  InfoPanel->Update();
13240 // erase track elements
13241  int LowSelectHLoc = SelectBitmapHLoc;
13242  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
13243  int LowSelectVLoc = SelectBitmapVLoc;
13244  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
13245  bool TrackEraseSuccessfulFlag; // needed but not used here
13246  int ErasedTrackVectorPosition;
13247 // new quick method of erasing, only need H & V values
13248  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
13249  {
13250  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
13251  {
13252  Track->EraseTrackElement(5, x, y, ErasedTrackVectorPosition, TrackEraseSuccessfulFlag, false);
13253  if(ErasedTrackVectorPosition > -1)
13254  EveryPrefDir->RealignAfterTrackErase(2, ErasedTrackVectorPosition);
13255  }
13256  }
13257 
13258 // erase text elements that fall within region to be overwritten
13259  int LowSelectHPos = SelectBitmapHLoc * 16;
13260  int HighSelectHPos = (SelectBitmapHLoc * 16) + SelectBitmap->Width;
13261  int LowSelectVPos = SelectBitmapVLoc * 16;
13262  int HighSelectVPos = (SelectBitmapVLoc * 16) + SelectBitmap->Height;
13263  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
13264  {
13265  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
13266  TextPtr--) // reverse to prevent skipping during erase
13267  {
13268  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
13269  HighSelectVPos))
13270  {
13271  if(TextHandler->TextErase(2, TextPtr->HPos, TextPtr->VPos))
13272  {;
13273  } // unused condition
13274  }
13275  }
13276  }
13277 // erase graphic elements that fall wholly within region to be overwritten
13278  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
13279  {
13280  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
13281  GraphicPtr--) // reverse to prevent skipping during erase
13282  {
13283  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
13284  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
13285  {
13286  Track->UserGraphicVector.erase(GraphicPtr);
13287  }
13288  }
13289  }
13290  // change the H & V values in SelectVector to the new positions in case Reselect chosen
13291  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
13292  {
13293  Track->SelectVectorAt(35, x).HLoc += HDiff;
13294  Track->SelectVectorAt(1, x).VLoc += VDiff;
13295  }
13296 
13297  // add the new track elements
13298  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
13299  {
13300  if(Track->CopyFlag) // blank all names if copying, lengths & speedlimits stay
13301  {
13302  Track->SelectVectorAt(80, x).LocationName = "";
13304  }
13305  bool InternalChecks = false;
13306 // if(Track->PastingWithAttributes) //new at v2.2.0 to select the new funtion & skip multimap checks //drop in v2.4.0
13307 // {
13309  TrackLinkingRequiredFlag, InternalChecks);
13310  // new at v2.2.0 & used in place of PlotAndAddTrackElement to keep length & speed values
13311 // }
13312 /* drop this in v2.4.0 as all pastes are past with attributes
13313  else //'Aspect' parameter added to PlotAndAdd... at v2.2.0 so can plot signals correctly (always four-aspect before)
13314  {
13315  int Aspect;
13316  if(Track->SelectVectorAt(15, x).TrackType != SignalPost) Aspect = 0; //if an '0' value appears with a SignalPost then must be adding track
13317  //this combination allows the funtion to distinguish between adding track and plotting with attributes
13318  else if(Track->SelectVectorAt(16, x).SigAspect == TTrackElement::GroundSignal) Aspect = 1;
13319  else if(Track->SelectVectorAt(17, x).SigAspect == TTrackElement::TwoAspect) Aspect = 2;
13320  else if(Track->SelectVectorAt(18, x).SigAspect == TTrackElement::ThreeAspect) Aspect = 3;
13321  else Aspect = 4;
13322  Track->PlotAndAddTrackElement(2, Track->SelectVectorAt(19, x).SpeedTag, Aspect, Track->SelectVectorAt(20, x).HLoc, Track->SelectVectorAt(21, x).VLoc, TrackLinkingRequiredFlag, InternalChecks);
13323  }
13324 */
13325  if(TrackLinkingRequiredFlag)
13326  NeedToLink = true;
13327  }
13328 
13329  if(!TextHandler->SelectTextVector.empty()) // skip iteration if empty else have an error
13330  {
13331  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->SelectTextVector.begin(); TextPtr < TextHandler->SelectTextVector.end(); TextPtr++)
13332  {
13333  TextPtr->HPos += HDiff * 16;
13334  TextPtr->VPos += VDiff * 16;
13335  AnsiString TempString = TextPtr->TextString;
13336  // have to create a new TextItem in order to create a new Font object
13337 /* drop in v2.4.0 as all pastes are paste with attributes
13338  if(!Track->PastingWithAttributes) //new at v2.2.0 to deal with the new location prefix '##**' //drop in v2.4.0
13339  {
13340  if(TextPtr->TextString.SubString(1,4) != "##**") //added for named locations so can delete in a simple paste but
13341  //use in PastingWithAttributes
13342  {
13343  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, TextPtr->TextString, TextPtr->Font);
13344  TextHandler->TextVectorPush(0, TextItem); //if a normal paste include normal text but not location text
13345  }
13346  else TextPtr->TextString = ""; //delete the name for a simple paste
13347  }
13348 */
13349 // else //if pasting with attributes paste all text but strip the '##**' prefix if present
13350 // {
13351  if(TextPtr->TextString.SubString(1, 4) == "##**")
13352  {
13353  TempString = TextPtr->TextString.SubString(5, TextPtr->TextString.Length()); // don't change SelectTextVector value
13354  if(Track->CopyFlag)
13355  {
13356  TextPtr->TextString = ""; // change SelectTextVector value as reselect shouldn't have locations if copied
13357  TempString = "";
13358  }
13359  }
13360  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, TempString, TextPtr->Font);
13362 // }
13363  }
13364  }
13365  // add new graphic items
13366  if(!Track->SelectGraphicVector.empty()) // skip iteration if empty else have an error
13367  { // keep contents of SelectVector valid in case reselect
13368  for(TTrack::TUserGraphicVector::iterator GraphicPtr = Track->SelectGraphicVector.begin(); GraphicPtr < Track->SelectGraphicVector.end();
13369  GraphicPtr++)
13370  {
13371  GraphicPtr->HPos += HDiff * 16; // for reselect
13372  GraphicPtr->VPos += VDiff * 16; // for reselect
13373  Track->UserGraphicVector.push_back(*GraphicPtr);
13374  }
13375  }
13376  Track->SkipLocationNameMultiMapCheck = false; // renamed in v2.4.0 - reset the flag after pasting complete, otherwise multimap checks always skipped
13377  Track->CopyFlag = false;
13378  Track->CheckMapAndTrack(7); // test
13379  Track->CheckMapAndInactiveTrack(7); // test
13380  Track->CheckLocationNameMultiMap(7); // test
13381  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
13382  // if track not linked to begin with then becomes linked if NeedToLink false
13383  if(NeedToLink)
13384  Track->SetTrackFinished(false); // corrected for v2.1.0
13385  Screen->Cursor = TCursor(-2); // Arrow;
13386  SetTrackBuildImages(14);
13389  SetLevel1Mode(79);
13391  // No further recursion in AddTrack so OK
13392  UserGraphicReselectPanel->Visible = false;
13393  SetLevel2TrackMode(42);
13394  } break;
13395 
13396  case Deleting:
13397  { // have to use braces as otherwise the default case bypasses the initialisation of these local variables
13398  Track->CopyFlag = false;
13399  UnicodeString MessageStr = "Selected area will be deleted - proceed?";
13400  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
13401  if(button == IDNO)
13402  {
13403  break;
13404  }
13405  bool EraseSuccessfulFlag, NeedToLink = false, TextChangesMade = false, GraphicChangesMade = false;
13406  int ErasedTrackVectorPosition;
13407  Screen->Cursor = TCursor(-11); // Hourglass;
13408  InfoPanel->Visible = true;
13409  InfoPanel->Caption = "DELETING: Please wait";
13410  InfoPanel->Update();
13411  for(int H = SelectRect.left; H < SelectRect.right; H++)
13412  {
13413  for(int V = SelectRect.top; V < SelectRect.bottom; V++)
13414  {
13415  Track->EraseTrackElement(3, H, V, ErasedTrackVectorPosition, EraseSuccessfulFlag, false);
13416  if(EraseSuccessfulFlag)
13417  {
13418  if(ErasedTrackVectorPosition > -1)
13419  EveryPrefDir->RealignAfterTrackErase(3, ErasedTrackVectorPosition);
13420  NeedToLink = true;
13421  }
13422  }
13423  }
13424  // erase text elements that fall within selected region
13425  int LowSelectHPos = SelectRect.left * 16;
13426  int HighSelectHPos = SelectRect.right * 16;
13427  int LowSelectVPos = SelectRect.top * 16;
13428  int HighSelectVPos = SelectRect.bottom * 16;
13429  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
13430  {
13431  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
13432  TextPtr--) // reverse to prevent skipping during erase
13433  {
13434  AnsiString Check = TextPtr->TextString;
13435  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
13436  HighSelectVPos))
13437  {
13438  if(TextHandler->TextErase(3, TextPtr->HPos, TextPtr->VPos))
13439  {;
13440  } // unused condition
13441  TextChangesMade = true;
13442  }
13443  }
13444  }
13445  // erase graphic elements that fall within selected region
13446  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
13447  {
13448  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->SelectGraphicVector.end() - 1); GraphicPtr >= Track->SelectGraphicVector.begin();
13449  GraphicPtr--) // reverse to prevent skipping during erase
13450  {
13451  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
13452  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
13453  {
13454  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = (Track->UserGraphicVector.end() - 1);
13455  UserGraphicPtr >= Track->UserGraphicVector.begin(); UserGraphicPtr--) // reverse to prevent skipping during erase
13456  {
13457  if((UserGraphicPtr->HPos == GraphicPtr->HPos) && (UserGraphicPtr->VPos == GraphicPtr->VPos) &&
13458  (UserGraphicPtr->Width == GraphicPtr->Width) && (UserGraphicPtr->Height == GraphicPtr->Height) &&
13459  (UserGraphicPtr->FileName == GraphicPtr->FileName))
13460  {
13461  Track->UserGraphicVector.erase(UserGraphicPtr);
13462  GraphicChangesMade = true;
13463  }
13464  }
13465  }
13466  }
13467  }
13468  // clear the selectvectors
13470  TextHandler->SelectTextVector.clear();
13471  Track->SelectGraphicVector.clear();
13472  Track->CheckMapAndTrack(10); // test
13473  Track->CheckMapAndInactiveTrack(9); // test
13474  Track->CheckLocationNameMultiMap(15); // test
13475  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
13476  // if track not linked to begin with then becomes linked if NeedToLink false
13477  if(NeedToLink)
13478  Track->SetTrackFinished(false); // corrected for v2.1.0
13479  if(NeedToLink || TextChangesMade || GraphicChangesMade)
13480  {
13481  ResetChangedFileDataAndCaption(21, true); // true for NonPrefDirChangesMade
13482  }
13483  Screen->Cursor = TCursor(-2); // Arrow;
13486  SetLevel1Mode(80);
13488  // No further recursion in AddTrack so OK
13489  UserGraphicReselectPanel->Visible = false;
13490  SetLevel2TrackMode(43);
13491  } break;
13492 
13493  default:
13494  // No further recursion in TrackMode so OK
13495  Track->CopyFlag = false;
13497  SetLevel1Mode(21);
13498  UserGraphicReselectPanel->Visible = false;
13499  break;
13500  }
13501  Utilities->CallLogPop(107);
13502 }
13503 
13504 // ---------------------------------------------------------------------------
13505 
13507 {
13508  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2PrefDirMode");
13509  if(Level1Mode != PrefDirMode)
13510  {
13511  // No further recursion in BaseMode so OK
13512  Level1Mode = BaseMode;
13513  SetLevel1Mode(22);
13514  Utilities->CallLogPop(108);
13515  return;
13516  }
13518  {
13519  Utilities->CallLogPop(109);
13520  return;
13521  }
13522 
13523  switch(Level2PrefDirMode) // use the data member
13524  {
13525  case PrefDirContinuing:
13526  { // have to use braces as otherwise the default case bypasses the initialisation of these local variables
13527  InfoPanel->Visible = true;
13528  if(!Display->ZoomOutFlag) // can't set focus if zoomed out, get an error - added this condition for v0.4d
13529  {
13530  AddPrefDirButton->Enabled = true; // this and the line below are to remove focus from any other button that might have it, prior to
13531  AddPrefDirButton->SetFocus(); // disabling the AddPrefDir button, so pressing enter does nothing, it is reset to the AddPrefDir
13532  }
13533  AddPrefDirButton->Enabled = false; // button later if it becomes enabled
13534  DeleteOnePrefDirButton->Enabled = false;
13535  bool LeadingPointsAtLastElement = false;
13536  if(!ConstructPrefDir->EndPossible(0, LeadingPointsAtLastElement))
13537  {
13538  if(LeadingPointsAtLastElement) // size must be > 1
13539  {
13540  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Can't end on leading points, select next location or truncate";
13541  DeleteOnePrefDirButton->Enabled = true;
13542  }
13543  else // size == 1, DeleteOnePrefDirButton->Enabled remains false
13544  {
13545  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Select next preferred direction location (right click to truncate)";
13546  }
13547  }
13548  else // size > 1 & EndPossible
13549  {
13550  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Add selection or select next location (right click to truncate)";
13551  if(!Display->ZoomOutFlag) // can't set focus if zoomed out, get an error - added this condition for v0.4d
13552  {
13553  AddPrefDirButton->Enabled = true;
13554  AddPrefDirButton->SetFocus(); // so can just press 'Enter' key
13555  }
13556  DeleteOnePrefDirButton->Enabled = true;
13557  }
13558  ExitPrefDirButton->Enabled = true;
13559  ClearandRebuildRailway(40); // to show truncated PrefDirs
13560  } break;
13561 
13562  case PrefDirSelecting:
13563  ResetSelectRect(); // so a viewpoint change before a new SelectRect chosen doesn't redisplay the old SelectRect
13564  InfoPanel->Visible = true;
13565  InfoPanel->Caption = "SELECTING: Select area - click left mouse && drag";
13566  SelectMenuItem->Enabled = false;
13567  ReselectMenuItem->Enabled = false;
13568  CancelSelectionMenuItem->Enabled = true;
13569  break;
13570 
13571  default:
13572  // No further recursion in PrefDirMode so OK
13574  SetLevel1Mode(23);
13575  break;
13576  }
13577  Utilities->CallLogPop(110);
13578 }
13579 
13580 // ---------------------------------------------------------------------------
13581 
13583 {
13584  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2OperMode");
13585  if(Level1Mode != OperMode)
13586  {
13587  // No further recursion in BaseMode so OK
13588  Level1Mode = BaseMode;
13589  SetLevel1Mode(24);
13590  Utilities->CallLogPop(111);
13591  return;
13592  }
13593  if(Level2OperMode == NoOperMode)
13594  {
13595  Utilities->CallLogPop(112);
13596  return;
13597  }
13598  CallingOnButton->Visible = true;
13599  PresetAutoSigRoutesButton->Visible = false;
13600  switch(Level2OperMode) // use the data member
13601  {
13602  case Operating:
13603  { // have to use braces as otherwise the default case bypasses the initialisation of local variables
13604  OperateButton->Enabled = true;
13605  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
13606  ExitOperationButton->Enabled = true;
13607  TTClockAdjButton->Enabled = false;
13608  if(TTClockSpeed == 2)
13609  TTClockSpeedLabel->Caption = "x2";
13610  else if(TTClockSpeed == 4)
13611  TTClockSpeedLabel->Caption = "x4";
13612  else if(TTClockSpeed == 8)
13613  TTClockSpeedLabel->Caption = "x8";
13614  else if(TTClockSpeed == 16)
13615  TTClockSpeedLabel->Caption = "x16";
13616  else if(TTClockSpeed == 0.5)
13617  TTClockSpeedLabel->Caption = "x1/2";
13618  else if(TTClockSpeed == 0.25)
13619  TTClockSpeedLabel->Caption = "x1/4";
13620  else if(TTClockSpeed == 0.125)
13621  TTClockSpeedLabel->Caption = "x1/8";
13622  else if(TTClockSpeed == 0.0625)
13623  TTClockSpeedLabel->Caption = "x1/16";
13624  else
13625  {
13626  TTClockSpeed = 1;
13627  TTClockSpeedLabel->Caption = "x1";
13628  }
13629  AnsiString TimeMessage = Utilities->Format96HHMMSS(TDateTime(PauseEntryRestartTime)) + ": ";
13631  {
13632  // send message to performance log
13633  if(TTClockSpeed == 2)
13634  Display->PerformanceLog(6, TimeMessage + "Timetable clock speed changed to twice normal");
13635  else if(TTClockSpeed == 4)
13636  Display->PerformanceLog(7, TimeMessage + "Timetable clock speed changed to four times normal");
13637  else if(TTClockSpeed == 8)
13638  Display->PerformanceLog(8, TimeMessage + "Timetable clock speed changed to eight times normal");
13639  else if(TTClockSpeed == 16)
13640  Display->PerformanceLog(9, TimeMessage + "Timetable clock speed changed to sixteen times normal");
13641  else if(TTClockSpeed == 0.5)
13642  Display->PerformanceLog(10, TimeMessage + "Timetable clock speed changed to half normal");
13643  else if(TTClockSpeed == 0.25)
13644  Display->PerformanceLog(11, TimeMessage + "Timetable clock speed changed to quarter normal");
13645  else if(TTClockSpeed == 0.125)
13646  Display->PerformanceLog(14, TimeMessage + "Timetable clock speed changed to one eighth normal");
13647  else if(TTClockSpeed == 0.0625)
13648  Display->PerformanceLog(15, TimeMessage + "Timetable clock speed changed to one sixteenth normal");
13649  else
13650  Display->PerformanceLog(12, TimeMessage + "Timetable clock speed changed to normal");
13651  }
13652  double TTClockTimeChange = double(TrainController->RestartTime) - PauseEntryRestartTime;
13653  if(TTClockTimeChange > 0.000347) // 30 seconds, min increase is 1 minute & don't trust doubles to stay exactly equal
13654  {
13655  // send message to performance log
13656  int MinsIncrease = ((TTClockTimeChange * 1440) + 0.5); // add 30 secs to ensure truncates correctly
13657  int HoursIncrease = 0;
13658  while(MinsIncrease >= 60)
13659  {
13660  HoursIncrease++;
13661  MinsIncrease -= 60;
13662  }
13663  if(HoursIncrease == 0)
13664  TimeMessage += "Timetable clock incremented by " + AnsiString(MinsIncrease) + "m";
13665  else if(MinsIncrease == 0)
13666  TimeMessage += "Timetable clock incremented by " + AnsiString(HoursIncrease) + "h";
13667  else
13668  TimeMessage += "Timetable clock incremented by " + AnsiString(HoursIncrease) + "h " + AnsiString(MinsIncrease) + "m";
13669  Display->PerformanceLog(13, TimeMessage);
13670  }
13671  WarningHover = false;
13674  {
13675  MTBFEditBox->Visible = true;
13676  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
13677  MTBFEditBox->ReadOnly = true; // because this is not prestart mode
13678  MTBFLabel->Visible = true;
13679  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
13681  }
13682  else
13683  {
13684  MTBFEditBox->Visible = false;
13685  MTBFEditBox->Text = "";
13686  MTBFLabel->Visible = false;
13687  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
13689  }
13690  TrainController->BaseTime = TDateTime::CurrentDateTime();
13691 // StopTTClockFlag already false because TTClock stopped by condition "if(!TrainController->StopTTClockFlag && (Level2OperMode == Operating))" in MasterClockTimer function
13692  } break;
13693 
13694  case Paused:
13695  OperateButton->Enabled = true;
13696  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
13697  ExitOperationButton->Enabled = true;
13698  TTClockAdjButton->Enabled = true;
13703 // StopTTClockFlag stays false because TTClock stopped by condition "if(!TrainController->StopTTClockFlag && (Level2OperMode == Operating))" in MasterClockTimer function
13706  break;
13707 
13708  // don't need a separate case for PreStart
13709 
13710  default:
13711  // No further recursion in OperMode so OK
13712  Level1Mode = OperMode;
13713  SetLevel1Mode(25);
13714  break;
13715  }
13716  Utilities->CallLogPop(113);
13717 }
13718 
13719 // ---------------------------------------------------------------------------
13720 
13721 void TInterface::ApproachLocking(int Caller, TDateTime TTClockTime)
13722 {
13723  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ApproachLocking");
13724  float LockDelay = 120.0;
13725 
13726  if(!AllRoutes->LockedRouteVector.empty())
13727  {
13728  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
13729  {
13730  bool BreakFlag = false;
13731  if(AllRoutes->TrackIsInARoute(5, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
13732  {
13733  TOneRoute &Route = AllRoutes->GetModifiableRouteAt(0, LRVIT->RouteNumber);
13734  if((TTClockTime - LRVIT->LockStartTime) > TDateTime(LockDelay / 86400))
13735  {
13736  TrainController->LogEvent("LockedRouteRemoved," + AnsiString(LRVIT->TruncateTrackVectorPosition) + "," +
13737  AnsiString(LRVIT->LastTrackVectorPosition));
13738  while(Route.LastElementPtr(9)->GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
13739  { // examine the element one earlier in the route than the last
13740  if(!(AllRoutes->TrackIsInARoute(6, Route.LastElementPtr(10)->Conn[Route.LastElementPtr(11)->GetELinkPos()],
13741  Route.LastElementPtr(12)->ConnLinkPos[Route.LastElementPtr(13)->GetELinkPos()])))
13742  {
13743  BreakFlag = true;
13744  }
13745  AllRoutes->RemoveRouteElement(1, Route.LastElementPtr(14)->HLoc, Route.LastElementPtr(15)->VLoc, Route.LastElementPtr(16)->GetELink());
13746  if(BreakFlag)
13747  break; // train removed earlier element from route so stop here
13748  }
13749  if(!BreakFlag)
13750  { // still need to remove the element at the TruncateTrackVectorPosition
13751  if(Route.LastElementPtr(17)->GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
13752  {
13753  AllRoutes->RemoveRouteElement(2, Route.LastElementPtr(18)->HLoc, Route.LastElementPtr(19)->VLoc,
13754  Route.LastElementPtr(20)->GetELink());
13755  }
13756  }
13757  AllRoutes->CheckMapAndRoutes(10); // test
13758  AllRoutes->LockedRouteVector.erase(LRVIT);
13759  if(!Display->ZoomOutFlag)
13760  ClearandRebuildRailway(17); // to get rid of route graphics
13762  }
13763  }
13764  else
13765  {
13766  AllRoutes->LockedRouteVector.erase(LRVIT);
13767  // if end element not in route then a train must have entered it from the wrong end and erased the whole route,
13768  // hence no longer needed so get rid of it
13769  }
13770  }
13771  }
13772  Utilities->CallLogPop(743);
13773 }
13774 
13775 // ---------------------------------------------------------------------------
13776 
13777 void TInterface::ContinuationAutoSignals(int Caller, TDateTime TTClockTime)
13778 {
13779  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ContinuationAutoSignals");
13781  {
13783  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
13784  AutoSigVectorIT--)
13785  {
13786  // Below added at v2.1.0 to prevent locked autosig continuation routes from clearing signals
13787  // need to identify the Continuation element in the route & check if it's in a locked route. If it is then don't call
13788  // SetTrailingSignalsOnContinuationRoute as all signals must stay red.
13789  TPrefDirElement TempPrefDirElement;
13790  int TempLockedVectorNumber;
13791  int LastRouteElement = AllRoutes->GetFixedRouteAt(220, AutoSigVectorIT->RouteNumber).PrefDirSize() - 1;
13792  int TVNum = AllRoutes->GetFixedRouteAt(221, AutoSigVectorIT->RouteNumber).GetFixedPrefDirElementAt(246, LastRouteElement).GetTrackVectorPosition();
13793  // this will be a continuation (error thrown in SetTrailingSignalsOnContinuationRoute if not) & XLinkPos is always 0 for
13794  // route exiting at a continuation
13795  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(14, TVNum, 0, TempPrefDirElement, TempLockedVectorNumber))
13796  {
13797  continue;
13798  }
13799  // end of additions
13800  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->FirstDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 0))
13801  {
13802  AllRoutes->SetTrailingSignalsOnContinuationRoute(1, AutoSigVectorIT->RouteNumber, 0);
13803  AutoSigVectorIT->AccessNumber++;
13804  continue;
13805  }
13806  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->SecondDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 1))
13807  {
13808  AllRoutes->SetTrailingSignalsOnContinuationRoute(2, AutoSigVectorIT->RouteNumber, 1);
13809  AutoSigVectorIT->AccessNumber++;
13810  continue;
13811  }
13812  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->ThirdDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 2))
13813  {
13814  AllRoutes->SetTrailingSignalsOnContinuationRoute(3, AutoSigVectorIT->RouteNumber, 2);
13815  AutoSigVectorIT->AccessNumber++;
13816  continue;
13817  }
13818  }
13819  // examine all vector for any expired values & erase
13820  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
13821  AutoSigVectorIT--)
13822  {
13823  if(AutoSigVectorIT->AccessNumber > 2)
13824  {
13825  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT); // erase expired entries - reverse interation so OK to erase
13826  }
13827  }
13828  }
13829  Utilities->CallLogPop(744);
13830 }
13831 
13832 // ---------------------------------------------------------------------------
13833 
13835 {
13836  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackTrainFloat");
13837 
13838  TPoint MousePoint = Mouse->CursorPos;
13839  int ScreenX = MousePoint.x - MainScreen->ClientOrigin.x;
13840  int ScreenY = MousePoint.y - MainScreen->ClientOrigin.y;
13841 
13842  if((ScreenX > (MainScreen->Width - 1)) || (ScreenY > (MainScreen->Height - 1)) || (ScreenX < 0) || (ScreenY < 0))
13843  {
13844  FloatingPanel->Visible = false;
13845  Utilities->CallLogPop(1432);
13846  return;
13847  }
13848 
13849  if(PerformancePanel->Visible)
13850  {
13851  if((MousePoint.x >= PerformancePanel->Left) && (MousePoint.x <= (PerformancePanel->Left + PerformancePanel->Width)) &&
13852  ((MousePoint.y - ClientOrigin.y) >= PerformancePanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
13853  (PerformancePanel->Top + PerformancePanel->Height)))
13854  { // dont show floating window if mouse over performance panel
13855  FloatingPanel->Visible = false;
13856  Utilities->CallLogPop(1715);
13857  return;
13858  }
13859  }
13860 
13861  if(OperatorActionPanel->Visible) // added at v2.3.0 as showed info from behind panel - thanks to Xeon who notified me in email of 15/10/19
13862  {
13863  if((MousePoint.x >= OperatorActionPanel->Left) && (MousePoint.x <= (OperatorActionPanel->Left + OperatorActionPanel->Width)) &&
13864  ((MousePoint.y - ClientOrigin.y) >= OperatorActionPanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
13865  (OperatorActionPanel->Top + OperatorActionPanel->Height)))
13866  { // dont show floating window if mouse over OperatorActionPanel
13867  FloatingPanel->Visible = false;
13868  Utilities->CallLogPop(2098);
13869  return;
13870  }
13871  }
13872 
13873  AnsiString TrackFloat = "", TrainStatusFloat = "", TrainTTFloat = "";
13874 
13875  bool ShowTrackFloatFlag = false, ShowTrainStatusFloatFlag = false, ShowTrainTTFloatFlag = false;
13876  int HLoc, VLoc;
13877 
13878  Track->GetTrackLocsFromScreenPos(4, HLoc, VLoc, ScreenX, ScreenY);
13879 
13880  if(Display->ZoomOutFlag)
13881  {
13882  Utilities->CallLogPop(1123);
13883  return;
13884  }
13885  if(TrackInfoOnOffMenuItem->Caption == "Hide")
13886  {
13887  bool ActiveTrackFoundFlag = false, InactiveTrackFoundFlag = false, TwoTrack = false;
13888  AnsiString Length01Str = "", Length23Str = "", SpeedLimit01Str = "", SpeedLimit23Str = "";
13889  AnsiString StationEntryStopLinkPos1Str = "", StationEntryStopLinkPos2Str = "";
13890  AnsiString ATrackSN = "", ATrackTN = "", IATrackSN = "", LengthAndSpeedCaption = "";
13891  AnsiString SigAspectString = ""; // new at version 0.6
13892  int ActiveVecPos = Track->GetVectorPositionFromTrackMap(5, HLoc, VLoc, ActiveTrackFoundFlag);
13893  TTrack::TIMPair InactiveVecPositions = Track->GetVectorPositionsFromInactiveTrackMap(3, HLoc, VLoc, InactiveTrackFoundFlag);
13894  TTrackElement ActiveTrackElement, InactiveTrackElement;
13895  if(InactiveTrackFoundFlag)
13896  {
13897  InactiveTrackElement = Track->InactiveTrackElementAt(32, InactiveVecPositions.first); // only need one for the name
13898  IATrackSN = InactiveTrackElement.LocationName;
13899  }
13900  if(ActiveTrackFoundFlag)
13901  {
13902  ActiveTrackElement = Track->TrackElementAt(449, ActiveVecPos);
13903  ATrackSN = ActiveTrackElement.LocationName;
13904  StationEntryStopLinkPos1Str = AnsiString(ActiveTrackElement.StationEntryStopLinkPos1);
13905  StationEntryStopLinkPos2Str = AnsiString(ActiveTrackElement.StationEntryStopLinkPos2);
13906  ATrackTN = ActiveTrackElement.ActiveTrackElementName;
13907  if((ATrackTN != "") && (!InactiveTrackFoundFlag || ((InactiveTrackElement.TrackType != Platform) &&
13908  (InactiveTrackElement.TrackType != NamedNonStationLocation)) ||
13909  (InactiveTrackElement.LocationName != ActiveTrackElement.ActiveTrackElementName)))
13910  {
13911  ShowMessage("Error - Track has timetable name without corresponding plat/named loc");
13912  }
13913  if(InactiveTrackFoundFlag && ((InactiveTrackElement.TrackType == Platform) || (InactiveTrackElement.TrackType == NamedNonStationLocation)) &&
13914  (InactiveTrackElement.LocationName != ActiveTrackElement.ActiveTrackElementName))
13915  {
13916  ShowMessage("Error - plat/named loc and track have different names, or plat/named loc named but not track");
13917  }
13918  if((ActiveTrackElement.TrackType == Points) || (ActiveTrackElement.TrackType == Bridge) || (ActiveTrackElement.TrackType == Crossover))
13919  {
13920  TwoTrack = true;
13921  }
13922  Length01Str = AnsiString(ActiveTrackElement.Length01);
13923  if(Length01Str == "-1")
13924  Length01Str = "Not Set";
13925  SpeedLimit01Str = AnsiString(ActiveTrackElement.SpeedLimit01);
13926  if(SpeedLimit01Str == "-1")
13927  SpeedLimit01Str = "Not Set";
13928  if(TwoTrack)
13929  {
13930  Length23Str = AnsiString(ActiveTrackElement.Length23);
13931  if(Length23Str == "-1")
13932  Length23Str = "Not Set"; // shouldn't be -1 but leave in
13933  SpeedLimit23Str = AnsiString(ActiveTrackElement.SpeedLimit23);
13934  if(SpeedLimit23Str == "-1")
13935  SpeedLimit23Str = "Not Set"; // shouldn't be -1 but leave in
13936  if((ActiveTrackElement.TrackType == Points) && (ActiveTrackElement.SpeedTag < 132))
13937  {
13938  LengthAndSpeedCaption = "Straight track length = " + Length01Str + " m" + '\n' + "Diverging track length = " + Length23Str + " m" + '\n' +
13939  "Straight track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Diverging track speed limit = " + SpeedLimit23Str + " km/h";
13940  }
13941  else if(ActiveTrackElement.TrackType == Points)
13942  {
13943  LengthAndSpeedCaption = "Left diverging track length = " + Length01Str + " m" + '\n' + "Right diverging track length = " + Length23Str +
13944  " m" + '\n' + "Left diverging track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Right diverging track Speed Limit = " +
13945  SpeedLimit23Str + " km/h";
13946  }
13947  else if(ActiveTrackElement.TrackType == Crossover)
13948  // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
13949  {
13950  if((ActiveTrackElement.SpeedTag == 15) || (ActiveTrackElement.SpeedTag == 46))
13951  {
13952  LengthAndSpeedCaption = "Horizontal track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str + " m" + '\n' +
13953  "Horizontal track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit23Str + " km/h";
13954  }
13955  else if(ActiveTrackElement.SpeedTag == 47)
13956  {
13957  LengthAndSpeedCaption = "Horizontal track length = " + Length23Str + " m" + '\n' + "Other track length = " + Length01Str + " m" + '\n' +
13958  "Horizontal track speed limit = " + SpeedLimit23Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit01Str + " km/h";
13959  }
13960  else if(ActiveTrackElement.SpeedTag == 45)
13961  {
13962  LengthAndSpeedCaption = "Vertical track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str + " m" + '\n' +
13963  "Vertical track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit23Str + " km/h";
13964  }
13965  else if(ActiveTrackElement.SpeedTag == 44)
13966  {
13967  LengthAndSpeedCaption = "Vertical track length = " + Length23Str + " m" + '\n' + "Other track length = " + Length01Str + " m" + '\n' +
13968  "Vertical track speed limit = " + SpeedLimit23Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit01Str + " km/h";
13969  }
13970  else if(ActiveTrackElement.SpeedTag == 16)
13971  {
13972  LengthAndSpeedCaption = "Top left to bottom right track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str +
13973  " m" + '\n' + "Top left to bottom right track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " +
13974  SpeedLimit23Str + " km/h";
13975  }
13976  }
13977  else // bridge
13978  {
13979  LengthAndSpeedCaption = "Top track length = " + Length01Str + " m" + '\n' + "Bottom track length = " + Length23Str + " m" + '\n' +
13980  "Top track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Bottom track speed limit = " + SpeedLimit23Str + " km/h";
13981  }
13982  }
13983  else
13984  {
13985  LengthAndSpeedCaption = "Track length = " + Length01Str + " m" + '\n' + "Track speed limit = " + SpeedLimit01Str + " km/h";
13986  }
13987  }
13988  if(ActiveTrackFoundFlag)
13989  {
13990  // note that now the "In timetable..." line removed much of the below could be simplified, but leave as is
13991  // in case wish to resurrect this line for any reason
13992  ShowTrackFloatFlag = true;
13993  if(ATrackTN != "") // has a timetable name & therefore has a valid platform or non-station name
13994  {
13995  TrackFloat = "Location = " + ATrackTN + '\n' + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
13996  }
13997  else if(ATrackSN != "") // no timetable name but location name, i.e. a footcrossing
13998  {
13999  TrackFloat = "Location = " + ATrackSN + '\n' + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
14000  }
14001 
14002  else if(InactiveTrackFoundFlag) // no timetable name yet but unnamed inactive element at same location (can't be a parapet if active element there)
14003  {
14004  TrackFloat = "Location unnamed\n" + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
14005  }
14006 
14007  else // no timetable or location name, just track
14008  {
14009  TrackFloat = LengthAndSpeedCaption + '\n' + "Track Element ID = " + AnsiString(ActiveTrackElement.ElementID);
14010  }
14011  if(ActiveTrackElement.TrackType == SignalPost) // new for version 0.6
14012  {
14013  if(ActiveTrackElement.SigAspect == TTrackElement::ThreeAspect)
14014  {
14015  SigAspectString = "\nThree-aspect signal";
14016  }
14017  else if(ActiveTrackElement.SigAspect == TTrackElement::TwoAspect)
14018  {
14019  SigAspectString = "\nTwo-aspect signal";
14020  }
14021  else if(ActiveTrackElement.SigAspect == TTrackElement::GroundSignal)
14022  {
14023  SigAspectString = "\nGround signal";
14024  }
14025  else
14026  {
14027  SigAspectString = "\nFour-aspect signal";
14028  }
14029  TrackFloat += SigAspectString;
14030  }
14031  } // if(ActiveFoundFlag)
14032  else if(InactiveTrackFoundFlag) // inactive element but no active element,
14033  // i.e. concourse or non-station name at a blank element
14034  {
14035  ShowTrackFloatFlag = true;
14036  if(InactiveTrackElement.TrackType != Parapet)
14037  {
14038  if(IATrackSN == "")
14039  {
14040  TrackFloat = "Location unnamed\nID = " + AnsiString(InactiveTrackElement.ElementID);
14041  }
14042  else
14043  {
14044  TrackFloat = "Location = " + IATrackSN + '\n' + "ID = " + AnsiString(InactiveTrackElement.ElementID);
14045  }
14046  }
14047  else // it is a parapet, just show the ID
14048  {
14049  TrackFloat = "ID = " + AnsiString(InactiveTrackElement.ElementID);
14050  }
14051  }
14052  }
14053 // end of TrackFloat section
14054 
14055  if(Level1Mode == OperMode && ((TrainStatusInfoOnOffMenuItem->Caption == "Hide Status") || (TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")))
14056  // if caption is 'Off' label is on
14057  {
14058  bool FoundFlag;
14059  AnsiString FormatOneDPStr = "####0.0";
14060  AnsiString FormatNoDPStr = "#######0";
14061 // AnsiString Format5DPStr = "####0.00000"; //temporary
14062  AnsiString MaxBrakeStr = ""; // , EntrySpeedStr="", HalfStr="", FullStr="", MaxAtHalfStr="";//test
14063  AnsiString SpecialStr = "", MaxSpeedStr = "";
14064  int VecPos = Track->GetVectorPositionFromTrackMap(6, HLoc, VLoc, FoundFlag);
14065  if(FoundFlag)
14066  {
14067  if(Track->TrackElementAt(450, VecPos).TrainIDOnElement > -1)
14068  // if a bridge & 2 trains at that position will select the train with TrainIDOnElement set
14069  {
14071  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
14072  {
14073  ShowTrainStatusFloatFlag = true;
14074  AnsiString HeadCode = "", ServiceReferenceInfo = "", Status = "", CurrSpeedStr = "", BrakePCStr = "", NextStopStr = "", TimeLeftStr = "",
14075  TimeToNextMovementStr = "", MassStr = "", PowerStr = "";
14076  double CurrSpeed;
14077  MassStr = AnsiString::FormatFloat(FormatNoDPStr, ((double)Train.Mass) / 1000); // Te
14078  PowerStr = AnsiString::FormatFloat(FormatNoDPStr, Train.PowerAtRail / 1000 / 0.8); // kW
14079  if(Train.BeingCalledOn)
14080  MaxSpeedStr = "30";
14081  else
14082  MaxSpeedStr = AnsiString::FormatFloat(FormatNoDPStr, Train.MaxRunningSpeed);
14083  TDateTime ElapsedDeltaT = TrainController->TTClockTime - Train.EntryTime;
14084  TDateTime FirstHalfTimeDeltaT = Train.ExitTimeHalf - Train.EntryTime;
14085  TDateTime SecondHalfTimeDeltaT = Train.ExitTimeFull - Train.EntryTime - FirstHalfTimeDeltaT;
14086  TDateTime TimeLeft;
14087  double BrakePCRate = Train.BrakeRate * 100.0 / Train.MaxBrakeRate;
14088  MaxBrakeStr = AnsiString::FormatFloat(FormatNoDPStr, (Train.MaxBrakeRate * Train.Mass / 9810));
14089  HeadCode = Train.HeadCode;
14090  if(Train.TrainDataEntryPtr->NumberOfTrains > 1) // Service reference information added at v0.6b
14091  {
14092  if(Train.RepeatNumber == 0)
14093  {
14094  if(HeadCode != Train.TrainDataEntryPtr->ServiceReference)
14095  ServiceReferenceInfo = "\nFirst service of ref. " + Train.TrainDataEntryPtr->ServiceReference;
14096  else
14097  ServiceReferenceInfo = "\nFirst service";
14098  }
14099  else if(HeadCode == Train.TrainDataEntryPtr->ServiceReference)
14100  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(Train.RepeatNumber);
14101  else
14102  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(Train.RepeatNumber) + " of ref. " +
14104  }
14105  else
14106  {
14107  if(HeadCode != Train.TrainDataEntryPtr->ServiceReference)
14108  ServiceReferenceInfo = "\nService reference " + Train.TrainDataEntryPtr->ServiceReference;
14109  }
14110  if(Train.Stopped())
14111  {
14112  if(Train.SignallerStopped)
14113  Status = "Stopped on signaller's instruction"; // if stopped for any other reason that will diplay
14114  if(Train.NotInService)
14115  Status = "Not in service"; // not used so far but leave it in
14116  if(Train.StoppedAtBuffers)
14117  Status = "Stopped at buffers";
14118  if(Train.StoppedAtSignal)
14119  Status = "Stopped at signal";
14120  if(Train.StoppedForTrainInFront)
14121  Status = "Stopped - forward track occupied"; // before station stop as want to display station stop if that set
14122  if(Train.StoppedAtLocation)
14123  Status = "Stopped at " + Train.ActionVectorEntryPtr->LocationName;
14124  if((Train.StoppedAtLocation) && (Train.StoppedForTrainInFront))
14125  Status = "Stopped at " + Train.ActionVectorEntryPtr->LocationName + " + forward track occupied";
14126  if(Train.StoppedWithoutPower)
14127  {
14128  if(Train.TrainFailed)
14129  Status = "Stopped without power - train failed";
14130  else
14131  Status = "Stopped without power";
14132  }
14133  if(Train.StoppedAfterSPAD)
14134  Status = "Stopped - signal passed at danger";
14135  if(Train.Derailed)
14136  Status = "Derailed";
14137  if(Train.Crashed)
14138  Status = "Crashed";
14139  CurrSpeed = 0;
14140  }
14141  else if(Train.OneLengthAccelDecel)
14142  {
14143  if(Train.FirstHalfMove)
14144  {
14145  Status = "Accelerating"; // just display a linear speed rise over half length
14146  BrakePCRate = 0; // reset to proper value during braking
14147  CurrSpeed = Train.EntrySpeed + ((Train.ExitSpeedHalf - Train.EntrySpeed) * (double(ElapsedDeltaT) / double(FirstHalfTimeDeltaT)));
14148  }
14149  else
14150  {
14151  BrakePCRate = Train.BrakeRate * 100.0 / Train.MaxBrakeRate;
14152  if(BrakePCRate < 55)
14153  Status = "Light braking";
14154  else if(BrakePCRate < 90)
14155  Status = "Heavy braking";
14156  else
14157  Status = "Emergency braking";
14158  CurrSpeed = Train.ExitSpeedHalf - 3.6 * (Train.BrakeRate * (TrainController->TTClockTime - Train.ExitTimeHalf) * 86400.0);
14159  }
14160  }
14161  else if(Train.BrakeRate > 0.01)
14162  {
14163  if(BrakePCRate < 55)
14164  Status = "Light braking";
14165  else if(BrakePCRate < 90)
14166  Status = "Heavy braking";
14167  else
14168  Status = "Emergency braking";
14169  CurrSpeed = Train.EntrySpeed - 3.6 * (Train.BrakeRate * ElapsedDeltaT * 86400.0);
14170  }
14171 
14172  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedHalf > (Train.EntrySpeed + 0.01)) && Train.FirstHalfMove)
14173  {
14174  Status = "Accelerating"; // just display a linear speed rise over half length
14175  CurrSpeed = Train.EntrySpeed + ((Train.ExitSpeedHalf - Train.EntrySpeed) * (double(ElapsedDeltaT) / double(FirstHalfTimeDeltaT)));
14176  }
14177 
14178  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedFull > (Train.ExitSpeedHalf + 0.01)) && !Train.FirstHalfMove)
14179  {
14180  Status = "Accelerating";
14181  CurrSpeed = Train.ExitSpeedHalf +
14182  ((Train.ExitSpeedFull - Train.ExitSpeedHalf) * (double(ElapsedDeltaT - FirstHalfTimeDeltaT) / double(SecondHalfTimeDeltaT)));
14183  }
14184 
14185  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedFull <= Train.ExitSpeedHalf) && !Train.FirstHalfMove)
14186  {
14187  if(Train.PowerAtRail < 1)
14188  {
14189  if(Train.TrainFailed)
14190  {
14191  Status = "Coasting - train failed";
14192  }
14193  else
14194  {
14195  Status = "Coasting - no power";
14196  }
14197  CurrSpeed = Train.ExitSpeedFull;
14198  }
14199  else
14200  {
14201  Status = "Constant speed";
14202  CurrSpeed = Train.ExitSpeedFull;
14203  }
14204  }
14205 
14206  else // No braking, first half move, ExitSpeedHalf <= EntrySpeed
14207  {
14208  if(Train.PowerAtRail < 1) // as designed there is no way a vehicle can coast without having failed
14209  {
14210  if(Train.TrainFailed)
14211  {
14212  Status = "Coasting - train failed";
14213  }
14214  else
14215  {
14216  Status = "Coasting - no power";
14217  }
14218  CurrSpeed = Train.ExitSpeedHalf;
14219  }
14220  else
14221  {
14222  Status = "Constant speed";
14223  CurrSpeed = Train.ExitSpeedHalf;
14224  }
14225  }
14226  if(Train.TimetableFinished)
14227  {
14228  if(Train.TrainMode == Signaller)
14229  NextStopStr = "At signaller's discretion";
14230  else
14231  NextStopStr = "None";
14232  }
14233  else
14234  NextStopStr = Train.FloatingLabelNextString(0, Train.ActionVectorEntryPtr);
14235  if(Train.TrainMode == Signaller)
14236  {
14237  SpecialStr = "Train under signaller control" + AnsiString('\n');
14238  }
14239  else if(Train.BeingCalledOn && !Train.StoppedAtLocation)
14240  {
14241  SpecialStr = "Restricted speed - being called on" + AnsiString('\n');
14242  }
14243 
14244  double RemTimeHalf = 86400.0 * double(Train.ExitTimeHalf - TrainController->TTClockTime);
14245  if(RemTimeHalf < 0)
14246  RemTimeHalf = 0;
14247  double RemTimeFull = 86400.0 * double(Train.ExitTimeFull - TrainController->TTClockTime);
14248  if(RemTimeFull < 0)
14249  RemTimeFull = 0;
14250  if(RemTimeHalf > 0)
14251  TimeLeft = RemTimeHalf;
14252  else
14253  TimeLeft = RemTimeFull;
14254  TimeToNextMovementStr = "Time to next movement (sec) = " + TimeLeftStr.FormatFloat(FormatOneDPStr, TimeLeft);
14255  if(Train.Stopped())
14256  TimeToNextMovementStr = "";
14257  if(Train.Stopped())
14258  {
14259  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " +
14260  MaxSpeedStr + "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr +
14261  Status + '\n' + "Next: " + NextStopStr;
14262  }
14263  else
14264  {
14265  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " +
14266  MaxSpeedStr + "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr +
14267  Status + ": " + CurrSpeedStr.FormatFloat(FormatNoDPStr, CurrSpeed) + "km/h" + '\n' + "Next: " + NextStopStr;
14268  }
14269  }
14270  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
14271  {
14272  ShowTrainTTFloatFlag = true;
14273  TrainTTFloat = Train.FloatingTimetableString(0, Train.ActionVectorEntryPtr);
14274  }
14275  }
14276 
14277  else if(Track->TrackElementAt(666, VecPos).TrackType == Continuation)
14278  // always give train information if a train present, but if not & either of train status or timetable info
14279  // selected then give next expected train to enter, or 'No trains expected'
14280  {
14281  TrainStatusFloat = "No trains expected";
14282  TrainTTFloat = "No timetable";
14283  float EntrySpeed;
14284  int LineSpeedLimit = Track->TrackElementAt(906, VecPos).SpeedLimit01; // speed only in 01 as a continuation
14285  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
14286  ShowTrainStatusFloatFlag = true;
14287  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
14288  ShowTrainTTFloatFlag = true;
14290  {
14293  {
14294  while((CTEIt != TrainController->ContinuationTrainExpectationMultiMap.end()) && ((CTEIt->second.VectorPosition != VecPos) ||
14295  (CTEIt->second.TrainDataEntryPtr->TrainOperatingDataVector.at(CTEIt->second.RepeatNumber).RunningEntry != NotStarted)))
14296  {
14297  CTEIt++;
14298  }
14300  {
14301  TTrainDataEntry *TTDEPtr = CTEIt->second.TrainDataEntryPtr;
14302  AnsiString ServiceReferenceInfo = "";
14303  // Repeat information
14304  if(TTDEPtr->NumberOfTrains > 1) // Service reference information
14305  {
14306  if(CTEIt->second.RepeatNumber == 0)
14307  {
14308  if(CTEIt->second.HeadCode != TTDEPtr->ServiceReference)
14309  ServiceReferenceInfo = "\nFirst service of ref. " + TTDEPtr->ServiceReference;
14310  else
14311  ServiceReferenceInfo = "\nFirst service";
14312  }
14313  else if(CTEIt->second.HeadCode == TTDEPtr->ServiceReference)
14314  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(CTEIt->second.RepeatNumber);
14315  else
14316  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(CTEIt->second.RepeatNumber) + " of ref. " +
14317  TTDEPtr->ServiceReference;
14318  }
14319  else
14320  {
14321  if(CTEIt->second.HeadCode != TTDEPtr->ServiceReference)
14322  ServiceReferenceInfo = "\nService reference " + TTDEPtr->ServiceReference;
14323  }
14324  if(TTDEPtr->ActionVector.at(0).SignallerControl) // entry at 0 is the start entry
14325  {
14326  SpecialStr = "\nTrain under signaller control";
14327  EntrySpeed = TTDEPtr->SignallerSpeed;
14328  if(EntrySpeed > LineSpeedLimit)
14329  EntrySpeed = LineSpeedLimit;
14330  }
14331  else
14332  {
14333  EntrySpeed = TTDEPtr->StartSpeed;
14334  if(EntrySpeed > LineSpeedLimit)
14335  EntrySpeed = LineSpeedLimit;
14336  }
14337  if((CTEIt->first + TDateTime(1.0 / 1440)) < TrainController->TTClockTime) // has to be at least 1 min late to show as late
14338  {
14339  TDateTime TempTime = CTEIt->first;
14340 // need this because CTEIt points to a const object and shouldn't use FormatString on a const object
14341  TrainStatusFloat = CTEIt->second.HeadCode + ": " + CTEIt->second.Description + ServiceReferenceInfo + "\nEntry speed " +
14342  AnsiString::FormatFloat(FormatNoDPStr, EntrySpeed) + "km/h" + SpecialStr + "\nDelayed, was due at " +
14343  Utilities->Format96HHMM(TempTime);
14344  }
14345  else
14346  {
14347  TDateTime TempTime = CTEIt->first;
14348 // need this because CTEIt points to a const object and shouldn't use FormatString on a const object
14349  TrainStatusFloat = CTEIt->second.HeadCode + ": " + CTEIt->second.Description + ServiceReferenceInfo + "\nEntry speed " +
14350  AnsiString::FormatFloat(FormatNoDPStr, EntrySpeed) + "km/h" + SpecialStr + "\nExpected at " +
14351  Utilities->Format96HHMM(TempTime);
14352  }
14353  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
14354  {
14355  if(!TTDEPtr->ActionVector.at(0).SignallerControl) // if signaller control there's no timetable & SpecialStr covers this
14356  {
14357  TrainTTFloat = TrainController->ContinuationEntryFloatingTTString(0, TTDEPtr, CTEIt->second.RepeatNumber,
14358  CTEIt->second.IncrementalMinutes, CTEIt->second.IncrementalDigits);
14359  }
14360  }
14361  }
14362  }
14363  }
14364  }
14365  }
14366  }
14367 
14368 // end of TrainFloat section
14369  AnsiString Caption;
14370 
14371  if(!ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
14372  {
14373  FloatingPanel->Visible = false;
14374  Utilities->CallLogPop(1485);
14375  return; // return with label invisible
14376  }
14377  else if(ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
14378  {
14379  Caption = TrackFloat;
14380  }
14381  else if(!ShowTrackFloatFlag && ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
14382  {
14383  Caption = TrainStatusFloat;
14384  }
14385  else if(ShowTrackFloatFlag && ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
14386  {
14387  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
14388  }
14389  else if(!ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
14390  {
14391  if(TrainStatusFloat == "No trains expected")
14392  Caption = TrainStatusFloat;
14393  else
14394  Caption = TrainTTFloat;
14395  }
14396  else if(ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
14397  {
14398  if(TrainStatusFloat == "No trains expected")
14399  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
14400  else
14401  Caption = TrainTTFloat + '\n' + '\n' + TrackFloat;
14402  }
14403  else if(!ShowTrackFloatFlag && ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
14404  {
14405  if(TrainStatusFloat == "No trains expected")
14406  Caption = TrainStatusFloat;
14407  else
14408  Caption = TrainStatusFloat + '\n' + '\n' + TrainTTFloat;
14409  }
14410  else if(ShowTrackFloatFlag && ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
14411  {
14412  if(TrainStatusFloat == "No trains expected")
14413  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
14414  else
14415  Caption = TrainStatusFloat + '\n' + '\n' + TrainTTFloat + '\n' + '\n' + TrackFloat;
14416  }
14417 
14418  int Left = ScreenX + MainScreen->Left + 16; // so lhs of window is one element to the right of the mouse pos
14419 
14420 // this offset is because window position is relative to the interface form, whereas ScreenX & Y are relative to the MainScreen, which is
14421 // offset 32 to the right and 95 down from the interface form
14422  if((Left + FloatingPanel->Width) > MainScreen->Left + MainScreen->Width)
14423  Left = ScreenX - FloatingPanel->Width + 16; // so rhs of window is one element to the left of the mouse pos (+32 would be at mouse pos)
14424  int Top = ScreenY + MainScreen->Top + 16; // so top of window is one element below the mouse pos (ScreenY + MainScreen->Top would be at mouse pos)
14425 
14426  if((Top + FloatingPanel->Height) > MainScreen->Top + MainScreen->Height)
14427  {
14428  Top = ScreenY - FloatingPanel->Height + 79; // so bottom of window is one element above the mouse pos (95 would be at mouse pos)
14429  // but, top may now be off the top of the screen, if so position at the top of the screen, as always need to see the top, if have to
14430  // lose something then it's best to be from the bottom
14431  if(Top < 30) // use 30 instead of MainScreen->Top [95] as top can go off MainScreen providing it doesn't reach the information panel, as that would
14432  // obscure the window
14433  {
14434  Top = 30;
14435  }
14436  }
14437  if((Left != FloatingPanel->Left) || (Top != FloatingPanel->Top))
14438  {
14439  FloatingPanel->Visible = false; // so doesn't flicker when reposition
14440  FloatingPanel->Left = Left;
14441  FloatingPanel->Top = Top;
14442  Utilities->CallLogPop(1917);
14443  return;
14444  }
14445 
14446  FloatingLabel->Caption = Caption;
14447  FloatingPanel->Visible = true;
14448  FloatingPanel->BringToFront();
14449  Utilities->CallLogPop(746);
14450 }
14451 
14452 // ---------------------------------------------------------------------------
14453 
14454 void TInterface::FlashingGraphics(int Caller, TDateTime Now)
14455  // following section checks to see if GapFlashFlag set & flashes the Gap graphics if so
14456  // Gap flashing is cancelled on any mousedown event
14457 
14458  // deal with flashing GapFlash graphics (only in basic mode so no need to check for trains)
14459 {
14460  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FlashingGraphics");
14462  {
14463  if(WarningFlash)
14464  {
14465  Track->GapFlashGreen->PlotOverlay(4, Display); // only plotted if PlotOverlay reset
14467  }
14468  else
14469  {
14470  Track->GapFlashGreen->PlotOriginal(17, Display); // only plotted if PlotOverlay set
14472  }
14473  }
14474 
14476  {
14477  if(WarningFlash)
14478  {
14483  Display->Update();
14484  }
14485  else
14486  {
14491  Display->Update();
14492  }
14493  }
14494 
14495 // deal with other flashing graphics
14497  {
14498  if((Now - RouteFlashStartTime) < TDateTime(RouteFlashDuration / 86400))
14499  {
14500  // cancel if train is moving & arrives on any part of flashing route
14502  {
14503  Track->RouteFlashFlag = false;
14505  ClearandRebuildRailway(18); // because using ConstructRoute->RouteFlash.PlotOriginal() can plot wrong point fillet as well as
14506  // original (if proposed route would change point). With this can dispense with ConstructRoute->RouteFlash.PlotOriginal()
14507  Utilities->CallLogPop(75);
14508  return;
14509  }
14510 
14511  InfoPanel->Visible = true;
14512  if(Level2OperMode == PreStart)
14513  InfoPanel->Caption = "PRE-START: Route setting in progress";
14514  else
14515  InfoPanel->Caption = "OPERATING: Route setting in progress";
14516  if(WarningFlash)
14517  {
14519  }
14520  else
14521  {
14523  }
14524  }
14525  else
14526  {
14527 // ConstructRoute->RouteFlash.PlotOriginal(); don't need with clearand....
14528 // stop clock while converting route as can take several seconds
14529  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
14531  if(PreferredRouteFlag)
14533  else
14535  ConstructRoute->ClearRoute(); // clear it immediately after use so as not to clutter the errorlog
14536  TrainController->BaseTime = TDateTime::CurrentDateTime();
14538  Track->RouteFlashFlag = false;
14540  ClearandRebuildRailway(19); // if drop this ensure replot trains after replot routes else route will overwrite a train
14541  }
14542  }
14543 
14544  if(Track->RouteFlashFlag && Display->ZoomOutFlag) // must have entered RouteFlash from normal screen so button states stored
14545  // dropped ZoomOutButton when route or point flashing, but leave this section in in case need to reinstate
14546  // no need to call Clearand... as that is called when revert to normal mode
14547  {
14548  if((Now - RouteFlashStartTime) >= TDateTime(RouteFlashDuration / 86400))
14549  {
14550  Track->RouteFlashFlag = false;
14551  if(PreferredRouteFlag)
14552  {
14554  }
14555  else
14556  {
14558  }
14559  ConstructRoute->ClearRoute(); // clear it immediately after use so as not to clutter the errorlog
14560  }
14561  }
14562 
14564  {
14565  if((Now - PointFlashStartTime) < TDateTime((PointsFlashDuration) / 86400))
14566  {
14567  // cancel if train is present on or enters a flashing point, either selected or diverging
14569  {
14571  Track->PointFlashFlag = false;
14573  Utilities->CallLogPop(76);
14574  return;
14575  }
14577  {
14579  Track->PointFlashFlag = false;
14581  Utilities->CallLogPop(77);
14582  return;
14583  }
14584 
14585  if(WarningFlash)
14586  {
14589  }
14590  else
14591  {
14593  }
14594  }
14595  else
14596  {
14601  {
14605  }
14607  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
14608  Track->PointFlashFlag = false;
14610  }
14611  }
14612 
14614  // dropped ZoomOutButton when point flashing but leave this section in in case need to reinstate
14615  {
14616  if((Now - PointFlashStartTime) < TDateTime((PointsFlashDuration) / 86400))
14617  {
14621  {
14624  }
14625  Track->PointFlashFlag = false;
14627  }
14628  }
14629 // deal with level crossings
14630  if(!Track->ChangingLCVector.empty() && (Level2OperMode != Paused))
14631  {
14632  int H;
14633  int V;
14634  for(unsigned int x = 0; x < Track->ChangingLCVector.size(); x++)
14635  {
14636  H = Track->ChangingLCVector.at(x).HLoc;
14637  V = Track->ChangingLCVector.at(x).VLoc;
14638  if((Now - Track->ChangingLCVector.at(x).StartTime) < TDateTime((Track->ChangingLCVector.at(x).ChangeDuration) / 86400))
14639  // still flashing
14640  {
14641  if(WarningFlash)
14642  {
14643  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Raising) // closing to trains
14644  {
14645  Track->PlotRaisedLinkedLevelCrossingBarriers(1, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V, Display);
14646  }
14647  else
14648  {
14649  Track->PlotLoweredLinkedLevelCrossingBarriers(0, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
14650  Track->ChangingLCVector.at(x).ConsecSignals, Display);
14651  }
14652  }
14653  else
14654  {
14655  Track->PlotLCBaseElementsOnly(2, Track->ChangingLCVector.at(x).BarrierState, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
14656  Track->ChangingLCVector.at(x).ConsecSignals, Display);
14657  }
14658  }
14659  else
14660  // flashing period finished
14661  {
14662  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Raising)
14663  {
14664  Track->PlotRaisedLinkedLevelCrossingBarriers(2, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V, Display);
14665  Track->SetLinkedLevelCrossingBarrierAttributes(4, H, V, 0); // only set attr to 0 when fully raised
14666  // attributes set to 2 when changing state, now reset to 0, no other actions needed
14667  }
14668  else
14669  // barriers lowering
14670  {
14671  Track->PlotLoweredLinkedLevelCrossingBarriers(1, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
14672  Track->ChangingLCVector.at(x).ConsecSignals, Display);
14673  Track->SetLinkedLevelCrossingBarrierAttributes(5, H, V, 1); // only set attr to 1 when fully lowered
14674  bool FoundFlag;
14675  int TVPos = Track->GetVectorPositionFromTrackMap(46, H, V, FoundFlag);
14676  if(!FoundFlag)
14677  {
14678  throw Exception("Failed to find a route at LC position HLoc = " + (AnsiString)H + " VLoc = " + (AnsiString)V);
14679  }
14680  int RouteNumber;
14681  AllRoutes->GetRouteTypeAndNumber(24, TVPos, 0, RouteNumber); // use 0 for LinkPos, could be 1 or 0 as only a single track element
14682  // don't need returned value of RouteType
14683  if(RouteNumber > -1) // if train crashed then there won't be a routenumber
14684  {
14685  AllRoutes->GetFixedRouteAt(196, RouteNumber).SetRouteSignals(8);
14686  }
14687  }
14688  }
14689  }
14690  for(int x = Track->ChangingLCVector.size() - 1; x >= 0; x--)
14691  // now transfer lowering barrier object from the ChangingLCVector to the BarriersDownVector, reset the start timer (to time the barrier down period)
14692  // and erase the object from the ChangingLCVector
14693  {
14694  if(!Track->IsLCBarrierFlashingAtHV(0, Track->ChangingLCVector.at(x).HLoc, Track->ChangingLCVector.at(x).VLoc))
14695  {
14696  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Lowering)
14697  {
14698  Track->ChangingLCVector.at(x).StartTime = TrainController->TTClockTime;
14699  Track->ChangingLCVector.at(x).BarrierState = TTrack::Down;
14700  Track->BarriersDownVector.push_back(Track->ChangingLCVector.at(x));
14701  }
14702  Track->ChangingLCVector.erase(Track->ChangingLCVector.begin() + x);
14703  }
14704  }
14705  }
14706  Utilities->CallLogPop(747);
14707 }
14708 
14709 // ---------------------------------------------------------------------------
14710 
14712  // set boundary, Home, NewHome, ZoomOut, CallingOn buttons & menu items as appropriate
14713 {
14714  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetSaveMenuAndButtons");
14715 
14716 // set save railway buttons
14717  bool SaveRailwayButtonsFlag = true;
14718 
14719  SaveRailwayTBPButton->Visible = true;
14720  SaveRailwayPDPButton->Visible = true;
14721  SaveSessionButton->Visible = true;
14722  if(Level1Mode == OperMode)
14723  {
14725  {
14726  SaveRailwayButtonsFlag = false;
14727  }
14728  // set PresetAutoSigRoutesButton enabled or not
14729  // enable if PreStart & no routes set
14730  if((Level2OperMode == PreStart) && (AllRoutes->AllRoutesVector.empty()))
14731  {
14732  PresetAutoSigRoutesButton->Enabled = true;
14733  }
14734  else
14735  {
14736  PresetAutoSigRoutesButton->Enabled = false;
14737  }
14738  }
14739  else
14740  {
14742  {
14743  SaveRailwayButtonsFlag = false;
14744  }
14745  else if(SavedFileName != "")
14746  {
14747  if((SavedFileName[SavedFileName.Length()] == 'y') || (SavedFileName[SavedFileName.Length()] == 'Y')) // 'rly' file
14748  {
14749  if(!(Track->IsReadyForOperation()))
14750  {
14751  SaveRailwayButtonsFlag = false; // can't save under its old name as not now a .rly file
14752  }
14753  }
14754  }
14755  }
14756  if(SaveRailwayButtonsFlag && (Level1Mode == BaseMode))
14757  {
14758  SaveRailwayBaseModeButton->Visible = true;
14759  }
14760  else
14761  {
14762  SaveRailwayBaseModeButton->Visible = false;
14763  }
14764  SaveRailwayTBPButton->Enabled = SaveRailwayButtonsFlag;
14765  SaveRailwayPDPButton->Enabled = SaveRailwayButtonsFlag;
14766  SaveRailwayBaseModeButton->Enabled = SaveRailwayButtonsFlag;
14767  SaveSessionButton->Enabled = SaveRailwayButtonsFlag;
14768 
14769 // set formatted timetable menu item
14770  if(TimetableTitle == "")
14771  {
14772  ExportTTMenuItem->Enabled = false;
14773  }
14774  else
14775  {
14776  ExportTTMenuItem->Enabled = true;
14777  }
14778 
14779 // set info menu items
14781  {
14782  FloatingInfoMenu->Enabled = false;
14783  TrackInfoMenuItem->Enabled = false;
14784  TrainInfoMenuItem->Enabled = false;
14785  }
14786  else
14787  {
14788  FloatingInfoMenu->Enabled = true;
14789  TrackInfoMenuItem->Enabled = true;
14790  if(Level1Mode == OperMode)
14791  {
14792  TrainInfoMenuItem->Enabled = true;
14793  }
14794  else
14795  {
14796  TrainInfoMenuItem->Enabled = false;
14797  }
14798  }
14799 
14800 // set all bar CallingOnButton operational to begin with - no, causes flickering of button graphics,
14801 // work on internal flags & then set buttons according to final flag values, then graphic won't change unless
14802 // there has been a legitimate change of state since the last access
14803 
14804  bool ZoomFlag = true, HomeFlag = true, NewHomeFlag = true, ScreenLeftFlag = true, ScreenRightFlag = true, ScreenUpFlag = true, ScreenDownFlag = true,
14805  TrackBuildPanelEnabledFlag = true, PrefDirPanelEnabledFlag = true, OperatingPanelEnabledFlag = true, TimetablePanelEnabledFlag = true;
14806 
14807  AnsiString TrackBuildPanelLabelCaptionStr = "Build/modify";
14808  AnsiString PrefDirPanelLabelCaptionStr = "Preferred direction selection";
14809  AnsiString OperatingPanelLabelCaptionStr = "Operation";
14810  AnsiString TimetablePanelLabelCaptionStr = "Timetable editor";
14811 
14812  if(!Display->ZoomOutFlag)
14813  { // prevent if half a screen or less visible (width = 60, height = 36) [Note HLocMin & Max 1 greater than extreme element]
14815  ScreenLeftFlag = false; // 60 - 30
14817  ScreenRightFlag = false; // 60 - (60 - 30)
14819  ScreenUpFlag = false; // 36 - 18
14821  ScreenDownFlag = false; // 36 - (36 - 18)
14822  }
14823  else
14824  { // prevent if less than a quarter of a screen visible (width = 240, height = 144)
14826  ScreenLeftFlag = false; // 240 - 60
14828  ScreenRightFlag = false; // 240 - (240 - 60)
14830  ScreenUpFlag = false; // 144 - 36
14832  ScreenDownFlag = false; // 144 - (144 - 36)
14833  }
14835  {
14836  ZoomFlag = false;
14837  HomeFlag = false;
14838  NewHomeFlag = false;
14839  ScreenLeftFlag = false;
14840  ScreenRightFlag = false;
14841  ScreenUpFlag = false;
14842  ScreenDownFlag = false;
14843  }
14844 
14845  if(Display->ZoomOutFlag)
14846  {
14847 // NewHomeFlag = false;
14848  TrackBuildPanelEnabledFlag = false;
14849  TrackBuildPanelLabelCaptionStr = "Disabled";
14850  PrefDirPanelEnabledFlag = false;
14851  PrefDirPanelLabelCaptionStr = "Disabled";
14852  OperatingPanelEnabledFlag = false;
14853  OperatingPanelLabelCaptionStr = "Disabled";
14854  TimetablePanelEnabledFlag = false;
14855  TimetablePanelLabelCaptionStr = "Disabled";
14856  }
14857 
14858  if(Level1Mode == OperMode)
14859  {
14860  if(Track->RouteFlashFlag || Track->PointFlashFlag || TTClockAdjPanel->Visible == true) //TTClockAdjPanel added for v2.4.2 to keep it disabled after Clock2Stopped dropped
14861  {
14862  OperatingPanelEnabledFlag = false;
14863  OperatingPanelLabelCaptionStr = "Disabled";
14864  ZoomFlag = false;
14865  HomeFlag = false;
14866  NewHomeFlag = false;
14867  ScreenLeftFlag = false;
14868  ScreenRightFlag = false;
14869  ScreenUpFlag = false;
14870  ScreenDownFlag = false;
14871  SaveOperatingImageMenuItem->Enabled = false;
14872  }
14873  else
14874  {
14875  SaveOperatingImageMenuItem->Enabled = true;
14876  }
14877  }
14878 
14879  if(LocationNameTextBox->Visible)
14880  {
14881  ZoomFlag = false;
14882  HomeFlag = false;
14883  NewHomeFlag = false;
14884  ScreenLeftFlag = false;
14885  ScreenRightFlag = false;
14886  ScreenUpFlag = false;
14887  ScreenDownFlag = false;
14888  }
14889 
14890  if(TextBox->Visible) // added at v1.3.0 to prevent screen moving when movement keys pressed during text entry
14891  {
14892  ZoomFlag = false;
14893  HomeFlag = false;
14894  NewHomeFlag = false;
14895  ScreenLeftFlag = false;
14896  ScreenRightFlag = false;
14897  ScreenUpFlag = false;
14898  ScreenDownFlag = false;
14899  }
14900 
14901  if((Level1Mode == TimetableMode) && (TimetableEditPanel->Visible))
14902  // added at v1.3.0 to prevent screen moving when movement keys pressed during timetable compilation (allowed if TT hidden)
14903  {
14904  ZoomFlag = false;
14905  HomeFlag = false;
14906  NewHomeFlag = false;
14907  ScreenLeftFlag = false;
14908  ScreenRightFlag = false;
14909  ScreenUpFlag = false;
14910  ScreenDownFlag = false;
14911  }
14912 
14915  {
14916  ZoomFlag = false;
14917  }
14918 
14919  if(ZoomFlag)
14920  ZoomButton->Enabled = true;
14921  else
14922  ZoomButton->Enabled = false;
14923  if(HomeFlag)
14924  HomeButton->Enabled = true;
14925  else
14926  HomeButton->Enabled = false;
14927  if(NewHomeFlag)
14928  NewHomeButton->Enabled = true;
14929  else
14930  NewHomeButton->Enabled = false;
14931  if(ScreenLeftFlag)
14932  ScreenLeftButton->Enabled = true;
14933  else
14934  ScreenLeftButton->Enabled = false;
14935  if(ScreenRightFlag)
14936  ScreenRightButton->Enabled = true;
14937  else
14938  ScreenRightButton->Enabled = false;
14939  if(ScreenUpFlag)
14940  ScreenUpButton->Enabled = true;
14941  else
14942  ScreenUpButton->Enabled = false;
14943  if(ScreenDownFlag)
14944  ScreenDownButton->Enabled = true;
14945  else
14946  ScreenDownButton->Enabled = false;
14947  if(OperatingPanelEnabledFlag)
14948  OperatingPanel->Enabled = true;
14949  else
14950  OperatingPanel->Enabled = false;
14951  if(TrackBuildPanelEnabledFlag)
14952  TrackBuildPanel->Enabled = true;
14953  else
14954  TrackBuildPanel->Enabled = false;
14955  if(PrefDirPanelEnabledFlag)
14956  PrefDirPanel->Enabled = true;
14957  else
14958  PrefDirPanel->Enabled = false;
14959  if(TimetablePanelEnabledFlag)
14960  TimetablePanel->Enabled = true;
14961  else
14962  TimetablePanel->Enabled = false;
14963  TrackBuildPanelLabel->Caption = TrackBuildPanelLabelCaptionStr;
14964  PrefDirPanelLabel->Caption = PrefDirPanelLabelCaptionStr;
14965  OperatingPanelLabel->Caption = OperatingPanelLabelCaptionStr;
14966  TimetablePanelLabel->Caption = TimetablePanelLabelCaptionStr;
14967 
14968 // check if any CallingOnFlags set & set button accordingly
14969  if(Display->ZoomOutFlag)
14970  {
14971  CallingOnButton->Enabled = false;
14972  CallingOnButton->Down = false;
14973  }
14974  else
14975  {
14976  if(Level2OperMode == Operating)
14977  {
14978  bool CallOnValid = false;
14979  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
14980  {
14982  {
14983  CallingOnButton->Enabled = true;
14984  CallOnValid = true;
14985  }
14986  }
14987  if(!CallOnValid)
14988  {
14989  CallingOnButton->Enabled = false;
14990  CallingOnButton->Down = false;
14991  }
14992  }
14993  else
14994  {
14995  CallingOnButton->Enabled = false;
14996  CallingOnButton->Down = false;
14997  }
14998  }
14999  Utilities->CallLogPop(970);
15000 }
15001 
15002 // ---------------------------------------------------------------------------
15003 
15004 void TInterface::ErrorLog(int Caller, AnsiString Message)
15005 {
15006 // create an error file for diagnostic purposes called on detection of a runtime error
15007 
15008 // Note: For faults in ClockTimer2, after the catch block in ClockTimer2 which calls this function, execution continues from where
15009 // ClockTimer2 was called, so the Utilities->Clock2Stopped flag is cleared and the whole sequence repeats itself, including the fault, until
15010 // the user presses the Exit button. Note also that Utilities->CallLogPop, called when ClockTimer (not ClockTimer2) returns, pops the error
15011 // message off the back of the Utilities->CallLog, not the ClockTimer call. Hence entries keep stacking up, including the push_front entry
15012 // but not the push_back error entry, and when finally printed there is a whole series of entries for the one fault, the number
15013 // depending on the time taken to press Exit.
15014 // Hence introduce an ErrorLogCalledFlag, set to true on first call, and preventing further calls thereafter.
15015 
15016  if(ErrorLogCalledFlag)
15017  return;
15018 
15019  ErrorLogCalledFlag = true;
15020  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + "," + Message);
15021  Utilities->CallLog.push_front("Version: " + ProgramVersion + "; Time and date: " + Utilities->DateTimeStamp());
15022  SaveErrorFile();
15023  if((TempTTFileName != "") && FileExists(TempTTFileName))
15024  {
15025  DeleteFile(TempTTFileName);
15026  }
15027  Display->GetImage()->Visible = false;
15028  PerformancePanel->Visible = false;
15029  OperatorActionPanel->Visible = false; // new v2.2.0
15030  TrackBuildPanel->Visible = false;
15031  TrackElementPanel->Visible = false;
15032  LocationNameTextBox->Visible = false;
15033  TextBox->Visible = false;
15034  TrackLengthPanel->Visible = false;
15035  InfoPanel->Visible = false;
15036  PrefDirPanel->Visible = false;
15037  TimetablePanel->Visible = false;
15038  TimetableEditPanel->Visible = false;
15039  OperatingPanel->Visible = false;
15040  FloatingPanel->Visible = false;
15041  ModeMenu->Enabled = false;
15042  SigImagePanel->Visible = false; // new at v2.3.0
15043  FileMenu->Enabled = false;
15044  EditMenu->Enabled = false;
15045  FloatingInfoMenu->Enabled = false;
15046  HelpMenu->Enabled = false;
15047 // SaveHeaderMenu1->Enabled = false;
15048  ScreenLeftButton->Visible = false;
15049  ScreenRightButton->Visible = false;
15050  ScreenUpButton->Visible = false;
15051  ScreenDownButton->Visible = false;
15052  HomeButton->Visible = false;
15053  NewHomeButton->Visible = false;
15054  ZoomButton->Visible = false;
15055  PrefDirKey->Visible = false;
15056  DistanceKey->Visible = false;
15057  OutputLog1->Caption = "";
15058  OutputLog2->Caption = "";
15059  OutputLog3->Caption = "";
15060  OutputLog4->Caption = "";
15061  OutputLog5->Caption = "";
15062  OutputLog6->Caption = "";
15063  OutputLog7->Caption = "";
15064  OutputLog8->Caption = "";
15065  OutputLog9->Caption = "";
15066  OutputLog10->Caption = "";
15067  ErrorMessage->Visible = true;
15068  ErrorButton->Visible = true;
15069  Screen->Cursor = TCursor(-2); // Arrow; - in case was an hourglass
15070 // No need for Utilities->CallLogPop as the call log deque has already been written to file & the next action
15071 // is to close the program when the exit button is pressed
15072 }
15073 
15074 // ---------------------------------------------------------------------------
15075 
15077  // not used from v2.2.0 as now allow floating panel & label to overlie performance panel
15078 {
15079  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPerformancePanelObscuringFloatingLabel");
15080  if(FloatingPanel->Visible == false)
15081  {
15082  Utilities->CallLogPop(1205);
15083  return false;
15084  }
15085 // pptop >= flbot, ppbot <= fltop, ppleft >= flright, ppright <= flleft
15086  if((PerformancePanel->Top >= (FloatingPanel->Top + FloatingPanel->Height)) || ((PerformancePanel->Top + PerformancePanel->Height) <= FloatingPanel->Top) ||
15087  (PerformancePanel->Left >= (FloatingPanel->Left + FloatingPanel->Width)) || ((PerformancePanel->Left + PerformancePanel->Width) <= FloatingPanel->Left))
15088  {
15089  Utilities->CallLogPop(1206);
15090  return false;
15091  }
15092  else
15093  {
15094  Utilities->CallLogPop(1207);
15095  return true;
15096  }
15097 }
15098 // ---------------------------------------------------------------------------
15099 
15100 void TInterface::SetCaption(int Caller)
15101 {
15102 /*
15103  NamedRailway; RlyFile; NamedTimetable
15104  n x x "New railway under development";
15105  y n x RailwayTitle + ": under development";
15106  y y n RailwayTitle + ": no timetable loaded";
15107  y y y RailwayTitle + ", " + TimetableTitle;
15108 */
15109 
15110  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetCaption");
15111  if(RailwayTitle == "")
15112  Caption = "Railway: New railway under development";
15113  else if(!RlyFile)
15114  Caption = "Railway: " + RailwayTitle + " under development";
15115 // else if(TimetableTitle == "") Caption = "Railway: " + RailwayTitle + "; Timetable: none loaded";
15116  else if(TimetableTitle == "")
15117  Caption = "Railway: " + RailwayTitle; // changed at v2.1.0, no need to mention TT if none loaded
15118  else
15119  Caption = "Railway: " + RailwayTitle + "; Timetable: " + TimetableTitle;
15120  Utilities->CallLogPop(1208);
15121 }
15122 
15123 // ---------------------------------------------------------------------------
15124 
15125 void TInterface::ResetAll(int Caller)
15126 {
15127  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAll");
15128  LastNonCtrlOrShiftKeyDown = -1; // added at v2.4.2 to no key down
15130  Track->GapFlashRedPosition = -1;
15131  Track->GapFlashFlag = false;
15132  Track->RouteFlashFlag = false;
15133  Track->PointFlashFlag = false;
15135  AutoSigsFlag = false;
15136  PreventGapOffsetResetting = false;
15137 
15138  Utilities->Clock2Stopped = false;
15139  TTClockSpeed = 1;
15140  TTClockSpeedLabel->Caption = "x1";
15141  Track->SetTrackFinished(false);
15143  CurrentSpeedButton = 0; // not assigned yet
15145  StartX = 0;
15146  StartY = 0;
15147  mbLeftDown = false;
15149  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
15151  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect");
15153  WarningFlashCount = 0;
15154 
15155  Level1Mode = BaseMode;
15156  SetLevel1Mode(26);
15157  RouteMode = None;
15158  PreferredRoute = true;
15159  ConsecSignalsRoute = true;
15160  DevelopmentPanel->Visible = false;
15161 
15162  MainScreen->Canvas->CopyMode = cmSrcCopy;
15163  FloatingPanel->Visible = false;
15164  OverallDistance = 0;
15165  OverallSpeedLimit = -1;
15166  AllRoutes->RouteTruncateFlag = false;
15167  CallingOnButton->Down = false;
15168  Display->ZoomOutFlag = false;
15169  ScreenGridFlag = false;
15170  InfoCaptionStore = "";
15171  ErrorLogCalledFlag = false;
15172  ErrorMessage->Visible = false;
15173  TempCursorSet = false;
15174  TempCursor = TCursor(-2); // Arrow
15175  WholeRailwayMoving = false; // new at v2.1.0
15176 
15177  TrainController->TTClockTime = TDateTime(0); // default setting
15178  TTClockAdjPanel->Visible = false;
15180  SelectedTrainID = -1;
15181  SetTrackBuildImages(11);
15182 // TrackInfoOnOffMenuItem->Caption = "Show"; dropped these here at v1.2.0 so don't reset when load a session file
15183 // TrainStatusInfoOnOffMenuItem->Caption = "Show Status";
15184 // TrainTTInfoOnOffMenuItem->Caption = "Show Timetable";
15185  Track->CalcHLocMinEtc(8);
15186  FileChangedFlag = false;
15187  RlyFile = false;
15188  SaveSessionFlag = false;
15189  LoadSessionFlag = false;
15190  SelectionValid = false;
15191  TimetableChangedFlag = false;
15192  SavedFileName = "";
15193  RailwayTitle = "";
15194  TimetableTitle = "";
15195  SetCaption(1);
15196  CreateEditTTFileName = ""; // set to null to allow a check during error file saving, if not null save the tt being edited to the file
15197  // added for Beta v0.2b
15198  CreateEditTTTitle = ""; // as above
15199  AllRoutes->NextRouteID = 0;
15200  TTrain::NextTrainID = 0; // reset to 0 whenever enter operating mode
15201  TFont *TempFont = new TFont; // if try to alter MainScreen->Canvas->Font directly it won't change the style for some reason
15202 
15203  TempFont->Style.Clear();
15204  TempFont->Name = "MS Sans Serif"; // reset font, else stays set to last displayed text font
15205  TempFont->Size = 10;
15206  TempFont->Color = clB0G0R0;
15207  TempFont->Charset = (TFontCharset)(0);
15208  MainScreen->Canvas->Font->Assign(TempFont);
15209  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
15210  PerformancePanel->Left = MainScreen->Left;
15211  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height; // new v2.2.0
15212  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width; ; // new v2.2.0
15213  // ScreenRightButton->Left = MainScreen->Width + MainScreen->Left; //Button values changed at v2.1.0 to allow for screen resizing
15214  // ScreenLeftButton->Left = ScreenRightButton->Left;
15215  // ScreenUpButton->Left = ScreenRightButton->Left;
15216  // ScreenDownButton->Left = ScreenRightButton->Left;
15217  // HomeButton->Left = ScreenRightButton->Left;
15218  // NewHomeButton->Left = ScreenRightButton->Left;
15219  // ZoomButton->Left = ScreenRightButton->Left;
15220  DevelopmentPanel->Top = MainScreen->Top + MainScreen->Height - DevelopmentPanel->Height;
15221  DevelopmentPanel->Left = MainScreen->Left + MainScreen->Width - DevelopmentPanel->Width; ; // new v2.2.0
15222 
15223  delete TempFont;
15224  CtrlKey = false;
15225  ShiftKey = false;
15226  Utilities->CallLogPop(1209);
15227 }
15228 
15229 // ---------------------------------------------------------------------------
15230 
15232 {
15233  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrackBuildImages,");
15234  if((Level1Mode == OperMode) || RlyFile)
15235  {
15236  TrackLinkedImage->Visible = false;
15237  TrackNotLinkedImage->Visible = false;
15238  GapsSetImage->Visible = false;
15239  GapsNotSetImage->Visible = false;
15240  LocationNamesSetImage->Visible = false;
15241  LocationNamesNotSetImage->Visible = false;
15242  Utilities->CallLogPop(1114);
15243  return;
15244  }
15245  else
15246  {
15247  if(!Track->NoActiveTrack(9))
15248  {
15249  if(Track->IsTrackFinished())
15250  {
15251  TrackLinkedImage->Visible = true;
15252  TrackNotLinkedImage->Visible = false;
15253  }
15254  else
15255  {
15256  TrackNotLinkedImage->Visible = true;
15257  TrackLinkedImage->Visible = false;
15258  }
15259  }
15260  else
15261  {
15262  TrackLinkedImage->Visible = false;
15263  TrackNotLinkedImage->Visible = false;
15264  }
15265 
15266  if(!Track->NoGaps(1))
15267  {
15268  if(Track->GapsUnset(6))
15269  {
15270  GapsNotSetImage->Visible = true;
15271  GapsSetImage->Visible = false;
15272  }
15273  else
15274  {
15275  GapsNotSetImage->Visible = false;
15276  GapsSetImage->Visible = true;
15277  }
15278  }
15279  else
15280  {
15281  GapsNotSetImage->Visible = false;
15282  GapsSetImage->Visible = false;
15283  }
15284 
15286  {
15287  if(Track->LocationsNotNamed(0))
15288  {
15289  LocationNamesSetImage->Visible = false;
15290  LocationNamesNotSetImage->Visible = true;
15291  }
15292  else
15293  {
15294  LocationNamesSetImage->Visible = true;
15295  LocationNamesNotSetImage->Visible = false;
15296  }
15297  }
15298  else
15299  {
15300  LocationNamesSetImage->Visible = false;
15301  LocationNamesNotSetImage->Visible = false;
15302  }
15303  }
15304  Utilities->CallLogPop(1113);
15305 }
15306 
15307 // ---------------------------------------------------------------------------
15308 
15309 void TInterface::ResetChangedFileDataAndCaption(int Caller, bool NonPrefDirChangesMade)
15310 {
15311  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetChangedFileDataAndCaption");
15312  FileChangedFlag = true;
15313  if(NonPrefDirChangesMade)
15314  {
15315  if(RlyFile) // i.e. was a Railway file but major changes made so class as a new railway
15316  {
15317  RailwayTitle = "";
15318  TimetableTitle = "";
15319  SavedFileName = "";
15320  RlyFile = false;
15321  }
15322  TimetableTitle = ""; // should have been reset already during user mode change but include here also
15323  SetTrackBuildImages(15);
15324  }
15325  SetCaption(2);
15326  Utilities->CallLogPop(1210);
15327 }
15328 
15329 // ---------------------------------------------------------------------------
15330 
15331 void TInterface::SaveSession(int Caller)
15332 { // ExcessLCDownMins saved as string after ***Interface*** see below
15333  try
15334  {
15335  TrainController->LogEvent("SaveSession");
15336  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSession");
15337  AnsiString CurrentDateTimeStr = "", TimetableTimeStr = "", SessionFileStr = "";
15338  Screen->Cursor = TCursor(-11); // Hourglass;
15339  CurrentDateTimeStr = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
15340  // avoid characters in filename:= / \ : * ? " < > |
15341  TimetableTimeStr = Utilities->Format96HHMMSS(TrainController->TTClockTime);
15342  TimetableTimeStr = TimetableTimeStr.SubString(1, 2) + '.' + TimetableTimeStr.SubString(4, 2) + '.' + TimetableTimeStr.SubString(7, 2);
15343  SessionFileStr = CurDir + "\\" + SESSION_DIR_NAME + "\\Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
15344  "; " + TimetableTitle + ".ssn";
15345  std::ofstream SessionFile(SessionFileStr.c_str());
15346  if(!(SessionFile.fail()))
15347  {
15348  Utilities->SaveFileString(SessionFile, ProgramVersion + ": ***Interface***" + FloatToStr(TrainController->ExcessLCDownMins));
15349 // added ExcessLC... at v2.2.0 as omitted earlier
15350  SaveInterface(0, SessionFile);
15351  // save track elements
15352  Utilities->SaveFileString(SessionFile, "***Track***");
15353  if(Track->UserGraphicVector.empty())
15354  {
15355  Track->SaveTrack(4, SessionFile, false); // false for no graphics (**Active elements** saved as marker)
15356  }
15357  else
15358  {
15359  Track->SaveTrack(11, SessionFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
15360  }
15361  // save text elements
15362  Utilities->SaveFileString(SessionFile, "***Text***");
15363  TextHandler->SaveText(2, SessionFile);
15364  // save PrefDir elements
15365  Utilities->SaveFileString(SessionFile, "***PrefDirs***");
15366  EveryPrefDir->SavePrefDirVector(2, SessionFile);
15367  if(!Track->UserGraphicVector.empty())
15368  {
15369  // save user graphics
15370  Track->SaveUserGraphics(2, SessionFile);
15371  }
15372  // save routes
15373  Utilities->SaveFileString(SessionFile, "***Routes***");
15374  AllRoutes->SaveRoutes(0, SessionFile);
15375  // save LockedRoutes
15376  Utilities->SaveFileString(SessionFile, "***Locked routes***");
15377  TrainController->SaveSessionLockedRoutes(0, SessionFile);
15378  // save ContinuationAutoSigEntries
15379  Utilities->SaveFileString(SessionFile, "***ContinuationAutoSigEntries***");
15381  // save BarriersDownVector
15382  Utilities->SaveFileString(SessionFile, "***BarriersDownVector***");
15383  Track->SaveSessionBarriersDownVector(0, SessionFile);
15384  // save timetable
15385  Utilities->SaveFileString(SessionFile, "***Timetable***");
15386  if(!(SaveTimetableToSessionFile(0, SessionFile, SessionFileStr)))
15387  {
15388  SessionFile.close();
15389  DeleteFile(SessionFileStr);
15390  Screen->Cursor = TCursor(-2); // Arrow;
15391  TrainController->StopTTClockMessage(3, "Error saving file, unable to save session");
15392  Utilities->CallLogPop(1150);
15393  return;
15394  }
15395  // save TimetableClock
15396  Utilities->SaveFileString(SessionFile, "***TimetableClock***");
15397  Utilities->SaveFileDouble(SessionFile, double(TrainController->TTClockTime));
15398 
15399  // save trains
15400  Utilities->SaveFileString(SessionFile, "***Trains***");
15401  TrainController->SaveSessionTrains(0, SessionFile);
15402  // save performance file
15403  Utilities->SaveFileString(SessionFile, "***Performance file***");
15404  SavePerformanceFile(0, SessionFile);
15405  Utilities->SaveFileString(SessionFile, "***End of performance file***");
15406 // addition at v2.4.0 to save TrainController->AvHoursIntValue + any future additions
15407  Utilities->SaveFileString(SessionFile, "***Additions after v2.3.1***");
15410  Utilities->SaveFileString(SessionFile, "***Failed Trains***");
15411  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
15412  {
15414  {
15417  }
15418  }
15419  Utilities->SaveFileInt(SessionFile, -1); // marker for end of failed trains
15420  Utilities->SaveFileString(SessionFile, "End of file at v2.4.0");
15421 // end of v2.4.0 addition
15422  SessionFile.close();
15423  TrainController->StopTTClockMessage(4, "Session saved: Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " +
15424  RailwayTitle + "; " + TimetableTitle + ".ssn");
15425  LastNonCtrlOrShiftKeyDown = -1; //to restore the ability to reselect Ctrl S after a save (FormKeyUp doesn't work because the Interface form doesn't have focus)
15426  }
15427  else
15428  {
15429  TrainController->StopTTClockMessage(5, "Session file failed to open, session not saved. Ensure that there is a folder named " + SESSION_DIR_NAME +
15430  " in the folder where the 'Railway.exe' program file resides");
15431  }
15432  Screen->Cursor = TCursor(-2); // Arrow
15433  Utilities->CallLogPop(1141);
15434  }
15435  catch(const Exception &e)
15436  {
15437  ErrorLog(40, e.Message);
15438  }
15439 }
15440 
15441 // ---------------------------------------------------------------------------
15442 
15443 void TInterface::LoadSession(int Caller)
15444  // always loads in 'Paused' or 'PreStart' mode
15445 {
15446 // remember to load the timetable clock
15447 // no routes in build
15448 // prob need to set 'OperMode' then 'Paused', ensure have all info needed for these
15449 // set buttons enabled to correspond to flags on reloading. If no PrefDirs then disable all route buttons
15450 // set RlyFile true
15451  try
15452  {
15453  TrainController->LogEvent("LoadSession");
15454  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadSession");
15455  if(!ClearEverything(4))
15456  {
15457  Utilities->CallLogPop(1145);
15458  return;
15459  }
15460  LoadSessionDialog->Filter = "Session file (*.ssn)|*.ssn";
15461  if(LoadSessionDialog->Execute())
15462  {
15463  TrainController->LogEvent("LoadSession " + LoadSessionDialog->FileName);
15464  Screen->Cursor = TCursor(-11); // Hourglass;
15465  if(SessionFileIntegrityCheck(0, AnsiString(LoadSessionDialog->FileName).c_str()))
15466  // if(true)
15467  {
15468  std::ifstream SessionFile(AnsiString(LoadSessionDialog->FileName).c_str());
15469  if(!(SessionFile.fail()))
15470  {
15471  TrainController->AvHoursIntValue = 0; // initial value set at v2.4.0 in case not changed later
15472  TrainController->MTBFHours = 0; // initial value set at v2.4.0 in case not changed later
15473  AnsiString TempString = Utilities->LoadFileString(SessionFile);
15474 // "version + : ***Interface***" + at v2.2.0 ExcessLCDownMins (omitted earlier)
15475 
15476  int LastCharBeforeFloat = TempString.LastDelimiter('*'); // added at v2.2.0
15477  if((LastCharBeforeFloat == 0) || (LastCharBeforeFloat == TempString.Length()))
15478  // can't find it or no value for Excess LCDownMins, either way count as zero
15479  {
15481  }
15482  else
15483  {
15484  AnsiString FloatStr = TempString.SubString(LastCharBeforeFloat + 1, TempString.Length() - LastCharBeforeFloat);
15485  if(!Utilities->CheckStringDouble(FloatStr)) // returns false for empty string or invalid double
15486  {
15488  }
15489  else
15490  {
15491  TrainController->ExcessLCDownMins = FloatStr.ToDouble();
15492  }
15493  } // end of v2.2.0 * v2.4.0 additions
15494 
15495  LoadInterface(0, SessionFile);
15496  int TempDisplayOffsetH = Display->DisplayOffsetH; // stored as they are zeroed when track loaded
15497  int TempDisplayOffsetV = Display->DisplayOffsetV;
15498  int TempDisplayOffsetHHome = Display->DisplayOffsetHHome;
15499  int TempDisplayOffsetVHome = Display->DisplayOffsetVHome;
15500  bool GraphicsFollow = false;
15501  // load track elements
15502  TempString = Utilities->LoadFileString(SessionFile); // ***Track***"
15503  Track->LoadTrack(4, SessionFile, GraphicsFollow);
15504  // load text elements
15505  TempString = Utilities->LoadFileString(SessionFile); // ***Text***"
15506  TextHandler->LoadText(1, SessionFile);
15507  // load PrefDir elements
15508  TempString = Utilities->LoadFileString(SessionFile); // "***PrefDirs***"
15509  EveryPrefDir->LoadPrefDir(1, SessionFile);
15510  if(GraphicsFollow)
15511  {
15512  Track->LoadGraphics(1, SessionFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME); // include path to Graphics folder);
15513  }
15515  {
15516  SessionFile.close();
15517  Screen->Cursor = TCursor(-2); // Arrow;
15518  ShowMessage("Corruption in preferred direction section of the session file, session can't be loaded");
15519  Utilities->CallLogPop(1438);
15520  return;
15521  }
15522  // load routes
15523  TempString = Utilities->LoadFileString(SessionFile); // "***Routes***"
15524  if(!AllRoutes->LoadRoutes(0, SessionFile))
15525  {
15526  SessionFile.close();
15527  Screen->Cursor = TCursor(-2); // Arrow;
15528  ShowMessage("Corruption in route section of the session file, session can't be loaded");
15529  Utilities->CallLogPop(1439);
15530  return;
15531  }
15532  // load LockedRoutes
15533  TempString = Utilities->LoadFileString(SessionFile); // "***Locked routes***"
15534  TrainController->LoadSessionLockedRoutes(0, SessionFile);
15535  // load ContinuationAutoSigEntries
15536  TempString = Utilities->LoadFileString(SessionFile); // "***ContinuationAutoSigEntries***"
15538  // load BarriersDownVector if present, but ensure backwards compatibility with earlier files
15539  TempString = Utilities->LoadFileString(SessionFile); // "***BarriersDownVector***" or "***Timetable***"
15540  if(TempString == "***BarriersDownVector***")
15541  {
15542  Track->LoadBarriersDownVector(0, SessionFile);
15543  TempString = Utilities->LoadFileString(SessionFile); // "***Timetable***"
15544  }
15545  // load timetable (marker "***Timetable***" already loaded)
15546  if(!(LoadTimetableFromSessionFile(0, SessionFile)))
15547  {
15548  SessionFile.close();
15549  Screen->Cursor = TCursor(-2); // Arrow;
15550  ShowMessage("Unable to load timetable section of the session file, session can't be loaded");
15551  Utilities->CallLogPop(1151);
15552  return;
15553  }
15554  // TimetableTitle should be loaded at this stage - check
15555  if(TimetableTitle == "")
15556  {
15557  SessionFile.close();
15558  Screen->Cursor = TCursor(-2); // Arrow;
15559  throw Exception("TimetableTitle null in LoadSession");
15560  }
15561  // load timetable clock
15562  TempString = Utilities->LoadFileString(SessionFile); // ***TimetableClock***
15563  TrainController->RestartTime = TDateTime(Utilities->LoadFileDouble(SessionFile)); // ClockTime set in RestartSessionOperMode;
15564  // load trains
15565  TempString = Utilities->LoadFileString(SessionFile); // ***Trains***
15566  TrainController->LoadSessionTrains(0, SessionFile);
15567  // load performance file + populate the performance log
15568  TempString = Utilities->LoadFileString(SessionFile); // ***Performance file***
15569  // first reset the performance file name and open it before reloading it
15570  PerformanceFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
15571  // avoid characters in filename:= / \ : * ? " < > |
15572  PerformanceFileName = CurDir + "\\" + PERFLOG_DIR_NAME + "\\Log " + PerformanceFileName + "; " + RailwayTitle + "; " +
15573  TimetableTitle + ".txt";
15574  Utilities->PerformanceFile.open(PerformanceFileName.c_str(), std::ios_base::out);
15575  if(Utilities->PerformanceFile.fail())
15576  {
15577  ShowMessage("Performance logfile failed to open, logs won't be saved. Ensure that there is a folder named " + PERFLOG_DIR_NAME +
15578  " in the folder where the 'Railway.exe' program file resides");
15579  }
15580  // now reload the performance file
15581  LoadPerformanceFile(0, SessionFile);
15582  // addition at v2.4.0
15583  char TempChar;
15584  SessionFile.get(TempChar);
15585  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '*'
15586  {
15587  SessionFile.get(TempChar);
15588  }
15589  if(SessionFile.eof()) // end of file
15590  {
15593  SessionFile.close(); // no TrainController->AvHoursIntValue & no failed trains
15594  }
15595  else
15596  {
15597  AnsiString DummyStr = Utilities->LoadFileString(SessionFile); // "**Additions after v2.3.1***" discarded (first '*' loaded earlier)
15598  TrainController->AvHoursIntValue = Utilities->LoadFileInt(SessionFile); // TrainController->AvHoursIntValue added at v2.4.0
15599  TrainController->NumFailures = Utilities->LoadFileInt(SessionFile); // number of train failures
15600  TrainController->MTBFHours = TrainController->AvHoursIntValue; // TTClockSpeed set to 1 in RestartSessionMode so no need to include here
15601  // now load any failed trains along with their OriginalPowerAtRail values
15602  DummyStr = Utilities->LoadFileString(SessionFile); // discard "***Failed Trains***"
15603  int ID = Utilities->LoadFileInt(SessionFile); // train ID or -1 for no more failed trains
15604  double PowerDouble;
15605  while(ID != -1)
15606  {
15607  PowerDouble = Utilities->LoadFileDouble(SessionFile); // ok TrainVector loaded at this stage (loaded in LoadSessionTrains)
15610  ID = Utilities->LoadFileInt(SessionFile);
15611  }
15612  SessionFile.close();
15613  }
15614  // deal with other settings
15615  Display->DisplayOffsetH = TempDisplayOffsetH; // reset to saved values
15616  Display->DisplayOffsetV = TempDisplayOffsetV;
15617  Display->DisplayOffsetHHome = TempDisplayOffsetHHome;
15618  Display->DisplayOffsetVHome = TempDisplayOffsetVHome;
15619  // now set attributes to 1 for all LCs with barriers down
15620  for(unsigned int x = 0; x < Track->BarriersDownVector.size(); x++)
15621  {
15623  }
15624  Track->ChangingLCVector.clear();
15625  Track->CalcHLocMinEtc(10);
15627  SetLevel1Mode(27);
15628  if(Level2OperMode == PreStart)
15629  // this section added at v1.3.2 as otherwise only in MainScreenMouseDown2, and if load a session without clicking mouse on screen
15630  { // then delay unspecified though seems to be 0
15631  PointsFlashDuration = 0.0;
15634  }
15635  else
15636  {
15640  }
15641  RlyFile = true;
15642  SetCaption(3);
15644  }
15645  }
15646  else
15647  {
15648  ShowMessage("Session file integrity check failed, unable to load session.");
15649  }
15650  Screen->Cursor = TCursor(-2); // Arrow;
15651  }
15652  Utilities->CallLogPop(1146);
15653  }
15654  catch(const Exception &e)
15655  {
15656  if((e.Message.Pos("esource") > 0) || (e.Message.Pos("arameter") > 0)) // 'Resource or Parameter, avoid capitals as may be OS dependent
15657  {
15658  Screen->Cursor = TCursor(-2); // Arrow;
15659  OutputLog1->Caption = "";
15660  OutputLog2->Caption = "";
15661  OutputLog3->Caption = "";
15662  OutputLog4->Caption = "";
15663  OutputLog5->Caption = "";
15664  OutputLog6->Caption = "";
15665  OutputLog7->Caption = "";
15666  OutputLog8->Caption = "";
15667  OutputLog9->Caption = "";
15668  OutputLog10->Caption = "";
15669  UnicodeString MessageStr =
15670  "Insufficient memory available to load the file, and partial load likely to be corrupt. Application will terminate. Try loading the session as the first action after reloading the program.";
15671 // UnicodeString MessageStr = "Last train loaded = " + UnicodeString(TrainController->LastTrainLoaded); //for debugging session train loading for many trains
15672  Application->MessageBox(MessageStr.c_str(), L"Out of memory", MB_OK | MB_ICONERROR);
15673  Application->Terminate();
15674  }
15675  else
15676  {
15677  ErrorLog(41, e.Message);
15678  }
15679  }
15680 }
15681 
15682 // ---------------------------------------------------------------------------
15683 
15684 void TInterface::SaveInterface(int Caller, std::ofstream &SessionFile)
15685 {
15686  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveInterface");
15687  if(Level2OperMode == PreStart)
15688  Utilities->SaveFileString(SessionFile, AnsiString("PreStart"));
15689  else
15690  Utilities->SaveFileString(SessionFile, AnsiString("NotPreStart")); // covers both Paused & Operating
15691  Utilities->SaveFileString(SessionFile, RailwayTitle);
15692  Utilities->SaveFileString(SessionFile, TimetableTitle);
15693  Utilities->SaveFileBool(SessionFile, PreferredRoute);
15694  Utilities->SaveFileBool(SessionFile, ConsecSignalsRoute);
15695  Utilities->SaveFileBool(SessionFile, AutoSigsFlag);
15696  Utilities->SaveFileInt(SessionFile, Display->DisplayOffsetH);
15697  Utilities->SaveFileInt(SessionFile, Display->DisplayOffsetV);
15702  Utilities->SaveFileString(SessionFile, OutputLog1->Caption);
15703  Utilities->SaveFileString(SessionFile, OutputLog2->Caption);
15704  Utilities->SaveFileString(SessionFile, OutputLog3->Caption);
15705  Utilities->SaveFileString(SessionFile, OutputLog4->Caption);
15706  Utilities->SaveFileString(SessionFile, OutputLog5->Caption);
15707  Utilities->SaveFileString(SessionFile, OutputLog6->Caption);
15708  Utilities->SaveFileString(SessionFile, OutputLog7->Caption);
15709  Utilities->SaveFileString(SessionFile, OutputLog8->Caption);
15710  Utilities->SaveFileString(SessionFile, OutputLog9->Caption);
15711  Utilities->SaveFileString(SessionFile, OutputLog10->Caption);
15712 
15734  // ExcessLCDownMins saved after ***Interface*** at v2.2.0 (omitted in error earlier)
15735  Utilities->CallLogPop(1211);
15736 }
15737 
15738 // ---------------------------------------------------------------------------
15739 void TInterface::LoadInterface(int Caller, std::ifstream &SessionFile)
15740 {
15741  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadInterface");
15742  AnsiString OpMode = Utilities->LoadFileString(SessionFile);
15743 
15744  if(OpMode == "PreStart")
15746  else
15748  RailwayTitle = Utilities->LoadFileString(SessionFile);
15749  SavedFileName = CurDir + "\\" + RAILWAY_DIR_NAME + "\\" + RailwayTitle + ".rly";
15750 
15751  TimetableTitle = Utilities->LoadFileString(SessionFile);
15752  PreferredRoute = Utilities->LoadFileBool(SessionFile);
15753  ConsecSignalsRoute = Utilities->LoadFileBool(SessionFile);
15754  AutoSigsFlag = Utilities->LoadFileBool(SessionFile);
15755  Display->DisplayOffsetH = Utilities->LoadFileInt(SessionFile);
15756  Display->DisplayOffsetV = Utilities->LoadFileInt(SessionFile);
15761  OutputLog1->Caption = Utilities->LoadFileString(SessionFile);
15762  OutputLog2->Caption = Utilities->LoadFileString(SessionFile);
15763  OutputLog3->Caption = Utilities->LoadFileString(SessionFile);
15764  OutputLog4->Caption = Utilities->LoadFileString(SessionFile);
15765  OutputLog5->Caption = Utilities->LoadFileString(SessionFile);
15766  OutputLog6->Caption = Utilities->LoadFileString(SessionFile);
15767  OutputLog7->Caption = Utilities->LoadFileString(SessionFile);
15768  OutputLog8->Caption = Utilities->LoadFileString(SessionFile);
15769  OutputLog9->Caption = Utilities->LoadFileString(SessionFile);
15770  OutputLog10->Caption = Utilities->LoadFileString(SessionFile);
15771 
15779  TrainController->LateDeps = Utilities->LoadFileInt(SessionFile);
15793  Utilities->CallLogPop(1212);
15794 }
15795 
15796 // ---------------------------------------------------------------------------
15797 
15798 bool TInterface::CheckInterface(int Caller, std::ifstream &SessionFile)
15799 {
15800  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckInterface");
15801 
15802  AnsiString OpMode = "";
15803 
15804  if(!Utilities->CheckAndReadFileString(SessionFile, OpMode))
15805  {
15806  Utilities->CallLogPop(1767);
15807  return false;
15808  }
15809  else if((OpMode != "PreStart") && (OpMode != "NotPreStart"))
15810  {
15811  Utilities->CallLogPop(1768);
15812  return false;
15813  }
15814  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile)) // RailwayTitle
15815  {
15816  Utilities->CallLogPop(1213);
15817  return false;
15818  }
15819  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile)) // TimetableTitle
15820  {
15821  Utilities->CallLogPop(1214);
15822  return false;
15823  }
15824  if(!Utilities->CheckFileBool(SessionFile))
15825  {
15826  Utilities->CallLogPop(1216);
15827  return false;
15828  }
15829  if(!Utilities->CheckFileBool(SessionFile))
15830  {
15831  Utilities->CallLogPop(1217);
15832  return false;
15833  }
15834  if(!Utilities->CheckFileBool(SessionFile))
15835  {
15836  Utilities->CallLogPop(1218);
15837  return false;
15838  }
15839  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
15840  {
15841  Utilities->CallLogPop(1409);
15842  return false;
15843  }
15844  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
15845  {
15846  Utilities->CallLogPop(1486);
15847  return false;
15848  }
15849  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
15850  {
15851  Utilities->CallLogPop(1487);
15852  return false;
15853  }
15854  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
15855  {
15856  Utilities->CallLogPop(1488);
15857  return false;
15858  }
15859  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
15860  {
15861  Utilities->CallLogPop(1489);
15862  return false;
15863  }
15864  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
15865  {
15866  Utilities->CallLogPop(1528);
15867  return false;
15868  }
15869  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
15870  {
15871  Utilities->CallLogPop(1725);
15872  return false;
15873  }
15874  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
15875  {
15876  Utilities->CallLogPop(1726);
15877  return false;
15878  }
15879  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
15880  {
15881  Utilities->CallLogPop(1727);
15882  return false;
15883  }
15884  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
15885  {
15886  Utilities->CallLogPop(1728);
15887  return false;
15888  }
15889  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
15890  {
15891  Utilities->CallLogPop(1730);
15892  return false;
15893  }
15894  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
15895  {
15896  Utilities->CallLogPop(1731);
15897  return false;
15898  }
15899  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
15900  {
15901  Utilities->CallLogPop(1732);
15902  return false;
15903  }
15904  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
15905  {
15906  Utilities->CallLogPop(1733);
15907  return false;
15908  }
15909  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
15910  {
15911  Utilities->CallLogPop(1734);
15912  return false;
15913  }
15914  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
15915  {
15916  Utilities->CallLogPop(1789);
15917  return false;
15918  }
15919 
15920  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
15921  {
15922  Utilities->CallLogPop(1737);
15923  return false;
15924  }
15925  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
15926  {
15927  Utilities->CallLogPop(1738);
15928  return false;
15929  }
15930  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
15931  {
15932  Utilities->CallLogPop(1739);
15933  return false;
15934  }
15935  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
15936  {
15937  Utilities->CallLogPop(1740);
15938  return false;
15939  }
15940  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
15941  {
15942  Utilities->CallLogPop(1741);
15943  return false;
15944  }
15945  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
15946  {
15947  Utilities->CallLogPop(1742);
15948  return false;
15949  }
15950  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
15951  {
15952  Utilities->CallLogPop(1743);
15953  return false;
15954  }
15955  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
15956  {
15957  Utilities->CallLogPop(1744);
15958  return false;
15959  }
15960  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
15961  {
15962  Utilities->CallLogPop(1745);
15963  return false;
15964  }
15965  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
15966  {
15967  Utilities->CallLogPop(1746);
15968  return false;
15969  }
15970  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
15971  {
15972  Utilities->CallLogPop(1747);
15973  return false;
15974  }
15975  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
15976  {
15977  Utilities->CallLogPop(1748);
15978  return false;
15979  }
15980  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
15981  {
15982  Utilities->CallLogPop(1749);
15983  return false;
15984  }
15985  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
15986  {
15987  Utilities->CallLogPop(1750);
15988  return false;
15989  }
15990  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
15991  {
15992  Utilities->CallLogPop(1751);
15993  return false;
15994  }
15995  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
15996  {
15997  Utilities->CallLogPop(1752);
15998  return false;
15999  }
16000 
16001  if(!Utilities->CheckFileDouble(SessionFile))
16002  {
16003  Utilities->CallLogPop(1753);
16004  return false;
16005  }
16006  if(!Utilities->CheckFileDouble(SessionFile))
16007  {
16008  Utilities->CallLogPop(1754);
16009  return false;
16010  }
16011  if(!Utilities->CheckFileDouble(SessionFile))
16012  {
16013  Utilities->CallLogPop(1755);
16014  return false;
16015  }
16016  if(!Utilities->CheckFileDouble(SessionFile))
16017  {
16018  Utilities->CallLogPop(1756);
16019  return false;
16020  }
16021  if(!Utilities->CheckFileDouble(SessionFile))
16022  {
16023  Utilities->CallLogPop(1757);
16024  return false;
16025  }
16026  Utilities->CallLogPop(1219);
16027  return true;
16028 }
16029 
16030 // ---------------------------------------------------------------------------
16031 
16032 bool TInterface::SaveTimetableToSessionFile(int Caller, std::ofstream &SessionFile, AnsiString SessionFileStr)
16033 {
16034  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTimetableToSessionFile," + SessionFileStr);
16035  if(!FileExists(TempTTFileName))
16036  {
16037  Utilities->CallLogPop(1862);
16038  return false;
16039  }
16040 
16041  SessionFile.close(); // close & re-open in append & binary mode so LF characters copy as LFs & not CRLFs
16042  SessionFile.open(SessionFileStr.c_str(), std::ios_base::app | std::ios_base::binary); // file pointer set to end
16043 
16044  int Handle = FileOpen(TempTTFileName, fmOpenRead);
16045  int Count = 0;
16046 
16047  while(Handle < 0) // this type of file use failed when used in SaveTempTimetableFile when used to resave timetable.tmp from
16048  // temp .ttb file, but changed that to avoid so many rapid file actions in quick succession & been OK since
16049  // then, but nevertheless have 10 retries before giving message to be on safe side
16050  {
16051  Handle = FileOpen(TempTTFileName, fmOpenRead);
16052  Count++;
16053  Delay(1, 50); // 50mSec delay between tries
16054  if(Count > 10)
16055  {
16056  ShowMessage("Failed to open temporary timetable file. Unable to save the session");
16057  Utilities->CallLogPop(1221);
16058  return false;
16059  }
16060  }
16061 
16062  char *Buffer = new char[10000];
16063  int BytesRead;
16064 
16065  while(true)
16066  {
16067  BytesRead = FileRead(Handle, Buffer, 10000);
16068  SessionFile.write(Buffer, BytesRead);
16069  if(BytesRead < 10000)
16070  break;
16071  }
16072  delete Buffer;
16073  FileClose(Handle);
16074 
16075  SessionFile.close(); // close & re-open in append & text out mode as before so can write text
16076  SessionFile.open(SessionFileStr.c_str(), std::ios_base::app | std::ios_base::out); // file pointer set to end
16077 
16078  Utilities->SaveFileString(SessionFile, "***End***"); // marker for end of timetable
16079 // now need to save the TrainOperatingData so can be loaded back into the timetable as is
16080  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.size());
16081  for(unsigned int x = 0; x < TrainController->TrainDataVector.size(); x++)
16082  {
16083  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size());
16084  for(unsigned int y = 0; y < TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size(); y++)
16085  {
16086  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).TrainID);
16087  Utilities->SaveFileInt(SessionFile, (short)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).EventReported));
16088  Utilities->SaveFileInt(SessionFile, (short)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).RunningEntry));
16089  }
16090  }
16091  Utilities->CallLogPop(1220);
16092  return true;
16093 }
16094 
16095 // ---------------------------------------------------------------------------
16096 
16097 bool TInterface::SaveTimetableToErrorFile(int Caller, std::ofstream &ErrorFile, AnsiString ErrorFileStr, AnsiString TimetableFileName)
16098 {
16099  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTimetableToErrorFile," + ErrorFileStr + "," + TimetableFileName);
16100  if(!FileExists(TimetableFileName))
16101  {
16102  Utilities->CallLogPop(1863);
16103  return false;
16104  }
16105 
16106  ErrorFile.close(); // close & re-open in append & binary mode so LF characters copy as LFs & not CRLFs
16107  ErrorFile.open(ErrorFileStr.c_str(), std::ios_base::app | std::ios_base::binary); // file pointer set to end
16108 
16109  int Handle = FileOpen(TimetableFileName, fmOpenRead);
16110  int Count = 0;
16111 
16112  while(Handle < 0) // this type of file use failed when used in SaveTempTimetableFile when used to resave timetable.tmp from
16113  // temp .ttb file, but changed that to avoid so many rapid file actions in quick succession & been OK since
16114  // then, but nevertheless have 10 retries before giving message to be on safe side
16115  {
16116  Handle = FileOpen(TimetableFileName, fmOpenRead);
16117  Count++;
16118  Delay(5, 50); // 50mSec delay between tries
16119  if(Count > 10)
16120  {
16121  Utilities->CallLogPop(1835);
16122  return false;
16123  }
16124  }
16125 
16126  char *Buffer = new char[10000];
16127  int BytesRead;
16128 
16129  while(true)
16130  {
16131  BytesRead = FileRead(Handle, Buffer, 10000);
16132  ErrorFile.write(Buffer, BytesRead);
16133  if(BytesRead < 10000)
16134  break;
16135  }
16136  delete Buffer;
16137  FileClose(Handle);
16138 
16139  ErrorFile.close(); // close & re-open in append & text out mode as before so can write text
16140  ErrorFile.open(ErrorFileStr.c_str(), std::ios_base::app | std::ios_base::out); // file pointer set to end
16141 
16142  Utilities->SaveFileString(ErrorFile, "***End of timetable***"); // marker for end of timetable
16143  Utilities->CallLogPop(1836);
16144  return true;
16145 }
16146 
16147 // ---------------------------------------------------------------------------
16148 
16149 bool TInterface::LoadTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
16150  // the .ttb section is delimited by "***End***"
16151  // create the temporary timetable file in the working folder exactly like the original
16152 {
16153  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTimetableFromSessionFile");
16154  // reset all message flags, stops them being given twice (shouldn't be needed here but add for safety) //new at v2.4.0
16155  TrainController->SSHigh = false;
16156  TrainController->MRSHigh = false;
16157  TrainController->MRSLow = false;
16158  TrainController->MassHigh = false;
16159  TrainController->BFHigh = false;
16160  TrainController->BFLow = false;
16161  TrainController->PwrHigh = false;
16162  TrainController->SigSHigh = false;
16163  TrainController->SigSLow = false;
16164  if((TempTTFileName != "") && FileExists(TempTTFileName))
16165  {
16166  DeleteFile(TempTTFileName);
16167  }
16168  int TempTTFileNumber = 0;
16169 
16170  while(FileExists(CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp"))
16171  {
16172  TempTTFileNumber++;
16173  }
16174  TempTTFileName = CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp";
16175 
16176  std::ofstream TTBFile(TempTTFileName.c_str()); // use text mode as SessionFile is in text mode, so CRLFs read as LFs, and LFs write as CRLFs.
16177  int Count;
16178  char Zero = '\0';
16179 
16180  if(!TTBFile.fail())
16181  {
16182  char *Buffer = new char[10000]; // can't use LoadFileString as that expects a '\0' delimiter
16183  char TempChar = (char)(SessionFile.peek()); // have a look at the next character, if it's '\n'
16184  if(TempChar == '\n')
16185  SessionFile.get(TempChar); // then get rid of it, else leave it in as part of the first line
16186  if(!SessionFile.getline(Buffer, 10000, '\0'))
16187  {
16188  TTBFile.close();
16189  DeleteFile(TempTTFileName);
16190  delete Buffer;
16191  Utilities->CallLogPop(1222);
16192  return false;
16193  }
16194  Count = 0;
16195  for(int x = 0; x < 10000; x++)
16196  {
16197  if(Buffer[x] != '\0')
16198  Count++;
16199  else
16200  break;
16201  }
16202  while(AnsiString(Buffer) != "***End***")
16203  {
16204  TTBFile.write(Buffer, Count);
16205  TTBFile.write(&Zero, 1);
16206 // TTBFile.write(&NewLine, 1);
16207  if(!SessionFile.getline(Buffer, 10000, '\0'))
16208  {
16209  TTBFile.close();
16210  DeleteFile(TempTTFileName);
16211  delete Buffer;
16212  Utilities->CallLogPop(1223);
16213  return false;
16214  }
16215  Count = 0;
16216  for(int x = 0; x < 10000; x++)
16217  {
16218  if(Buffer[x] != '\0')
16219  Count++;
16220  else
16221  break;
16222  }
16223  }
16224  TTBFile.close();
16225  delete Buffer;
16226 // SaveTempTimetableFile(1, TTBFileName); no need, already has required name
16227 // now create the internal timetable from the .tmp file
16228  bool GiveMessagesFalse = false;
16229  bool CheckLocationsExistInRailwayTrue = true;
16230  if(TrainController->TimetableIntegrityCheck(1, TempTTFileName.c_str(), GiveMessagesFalse, CheckLocationsExistInRailwayTrue))
16231  {
16232  std::ifstream TTBLFile(TempTTFileName.c_str(), std::ios_base::binary);
16233  if(TTBLFile.is_open())
16234  {
16235  bool SessionFileTrue = true;
16236  if(!(BuildTrainDataVectorForLoadFile(1, TTBLFile, GiveMessagesFalse, CheckLocationsExistInRailwayTrue, SessionFileTrue)))
16237  {
16238  TTBLFile.close();
16239  DeleteFile(TempTTFileName);
16240  Utilities->CallLogPop(1224);
16241  return false;
16242  }
16243  }
16244  else
16245  {
16246  DeleteFile(TempTTFileName);
16247  Utilities->CallLogPop(1225);
16248  return false;
16249  }
16250  } // if(FileIntegrityCheck(TTBFileName.c_str()))
16251  else
16252  {
16253  DeleteFile(TempTTFileName);
16254  Utilities->CallLogPop(1226);
16255  return false;
16256  }
16257 // DeleteFile(TempTTFileName); no, need to save it for later session saves
16258 
16259  // now need to load the TrainOperatingData so can be loaded back into the timetable
16260  int NumberOfTrainEntries = Utilities->LoadFileInt(SessionFile);
16261  if(NumberOfTrainEntries != (int)(TrainController->TrainDataVector.size()))
16262  {
16263  Utilities->CallLogPop(1811);
16264  return false;
16265  }
16266  for(int x = 0; x < NumberOfTrainEntries; x++)
16267  {
16268  int NumberOfTrains = Utilities->LoadFileInt(SessionFile);
16269  if(NumberOfTrains != (int)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size()))
16270  {
16271  Utilities->CallLogPop(1812);
16272  return false;
16273  }
16274  for(int y = 0; y < NumberOfTrains; y++)
16275  {
16276  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).TrainID = Utilities->LoadFileInt(SessionFile);
16277  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).EventReported = (TActionEventType)(Utilities->LoadFileInt(SessionFile));
16278  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).RunningEntry = (TRunningEntry)(Utilities->LoadFileInt(SessionFile));
16279  }
16280  }
16281  Utilities->CallLogPop(1227);
16282  return true;
16283  }
16284  else
16285  {
16286  Utilities->CallLogPop(1228);
16287  return false;
16288  }
16289 }
16290 
16291 // ---------------------------------------------------------------------------
16292 
16293 bool TInterface::CheckTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
16294  // the .ttb section is delimited by '\0' followed by "***End***" & has been saved in binary mode, i.e. no '\0'
16295  // string delimiters between entries, this check function just checks the (non-zero terminated) string entries in the file without
16296  // trying to build a timetable - that's done during load
16297 {
16298  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTimetableFromSessionFile");
16299  AnsiString OutString;
16300 
16301  if(!Utilities->CheckAndReadFileString(SessionFile, OutString))
16302  {
16303  Utilities->CallLogPop(1229);
16304  return false;
16305  }
16306  while(OutString != "***End***")
16307  {
16308  if(!Utilities->CheckAndReadFileString(SessionFile, OutString))
16309  {
16310  Utilities->CallLogPop(1230);
16311  return false;
16312  }
16313  }
16314 // now need to check the TrainOperatingData, which was saved in text mode
16315  if(SessionFile.fail())
16316  {
16317  Utilities->CallLogPop(1231);
16318  return false;
16319  }
16320  int NumberOfTrainEntries;
16321 
16322  if(!Utilities->CheckAndReadFileInt(SessionFile, 0, 10000, NumberOfTrainEntries))
16323  {
16324  Utilities->CallLogPop(1232);
16325  return false;
16326  }
16327  for(int x = 0; x < NumberOfTrainEntries; x++)
16328  {
16329  int NumberOfTrains;
16330  if(!Utilities->CheckAndReadFileInt(SessionFile, 0, 10000, NumberOfTrains))
16331  {
16332  Utilities->CallLogPop(1233);
16333  return false;
16334  }
16335  for(int y = 0; y < NumberOfTrains; y++)
16336  {
16337  if(!Utilities->CheckFileInt(SessionFile, -1, 1000000)) // TrainID
16338  {
16339  Utilities->CallLogPop(1234);
16340  return false;
16341  }
16342  if(!Utilities->CheckFileInt(SessionFile, 0, 30)) // EventReported
16343  {
16344  Utilities->CallLogPop(1235);
16345  return false;
16346  }
16347  if(!Utilities->CheckFileInt(SessionFile, 0, 2)) // RunningEntry
16348  {
16349  Utilities->CallLogPop(1236);
16350  return false;
16351  }
16352  }
16353  }
16354  Utilities->CallLogPop(1237);
16355  return true;
16356 }
16357 
16358 // ---------------------------------------------------------------------------
16359 
16360 bool TInterface::BuildTrainDataVectorForLoadFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway, bool SessionFile)
16361 {
16362  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildTrainDataVectorForLoadFile," + AnsiString((short)GiveMessages));
16363  TrainController->TrainDataVector.clear(); // get rid of any earlier timetable
16364  bool EndOfFile = false;
16365  int Count = 0;
16366  char *TrainTimetableString = new char[10000]; // enough for ~ 200 stations at 50 chars/station, should be adequate!
16367 
16368  while(!EndOfFile)
16369  {
16370  TTBLFile.getline(TrainTimetableString, 10000, '\0');
16371  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
16372  { // may still have eof even if read a line (no CRLF at end), and
16373  // if so need to process it
16374  EndOfFile = true;
16375  break;
16376  }
16377  AnsiString OneLine(TrainTimetableString);
16378  bool FinalCallTrue = true;
16379  while((Count == 0) && !TrainController->ProcessOneTimetableLine(3, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages,
16380  CheckLocationsExistInRailway)) // get rid of lines before the start time
16381  {
16382  TTBLFile.getline(TrainTimetableString, 10000, '\0');
16383  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
16384  {
16385  TTBLFile.close();
16386  throw Exception("Timetable FinalCall error - no start time on own line, Count = 0");
16387  }
16388  OneLine = AnsiString(TrainTimetableString);
16389  }
16390  // here when have accepted the start time
16391  if(Count == 0)
16392  {
16393  Count++; // increment past the start time
16394  TTBLFile.getline(TrainTimetableString, 10000, '\0'); // get next line after start time
16395  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
16396  {
16397  EndOfFile = true;
16398  OneLine = "";
16399  }
16400  else
16401  OneLine = AnsiString(TrainTimetableString);
16402  }
16403  if(!TrainController->ProcessOneTimetableLine(4, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages, CheckLocationsExistInRailway))
16404  {
16405  TTBLFile.close();
16406  throw Exception("Timetable FinalCall error in processing one timetable line, Count = " + AnsiString(Count));
16407  }
16408  if(EndOfFile && (Count < 2)) // Timetable must contain at least two relevant lines, one for start time and at least one train
16409  {
16410  TTBLFile.close();
16411  throw Exception("Timetable FinalCall error - too few or no relevant entries, Count = " + AnsiString(Count));
16412  }
16413  Count++;
16414  }
16415  TTBLFile.close();
16416  delete TrainTimetableString;
16417 // here when first pass actions completed successfully
16418  if(!TrainController->SecondPassActions(0, GiveMessages)) // Check for matching join/split HeadCodes, check increasing times & matching split/join
16419  // times, complete arrival & departure times for each TT line, check & complete train info for each type of start,
16420  // messages given in function if errors & vector cleared
16421  {
16422  if(GiveMessages)
16423  ShowMessage("Timetable secondary integrity check failed - unable to load");
16424  Utilities->CallLogPop(1238);
16425  return false;
16426  }
16427  else
16428  {
16429 // TimetableLoaded = true;
16430  if(!SessionFile) // new timetable being loaded so need new TimetableTitle, if SessionFile true then already have it from LoadInterface
16431  {
16432  for(int x = TimetableDialog->FileName.Length(); x > 0; x--)
16433  {
16434  if(TimetableDialog->FileName[x] == '\\')
16435  {
16436  TimetableTitle = TimetableDialog->FileName.SubString(x + 1, TimetableDialog->FileName.Length() - x - 4);
16437  SetCaption(4);
16438  break;
16439  }
16440  }
16441  }
16442 // if(GiveMessages) //only set BaseMode if have manually loaded a timetable changed for the below in v2.4.0
16443  if(!SessionFile) // only set BaseMode if have manually loaded a timetable, i.e SessionFile is false
16444  {
16445  Level1Mode = BaseMode;
16446  SetLevel1Mode(28);
16447  }
16448  }
16449  Utilities->CallLogPop(1239);
16450  return true;
16451 }
16452 
16453 // ---------------------------------------------------------------------------
16454 
16455 bool TInterface::BuildTrainDataVectorForValidateFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway)
16456 {
16457  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildTrainDataVectorForValidateFile," + AnsiString((short)GiveMessages));
16458  TrainController->TrainDataVector.clear(); // get rid of any earlier timetable
16459  bool EndOfFile = false;
16460  int Count = 0;
16461  char *TrainTimetableString = new char[10000]; // enough for ~ 200 stations at 50 chars/station, should be adequate!
16462 
16463  while(!EndOfFile)
16464  {
16465  TTBLFile.getline(TrainTimetableString, 10000, '\0');
16466  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
16467  { // may still have eof even if read a line (no CRLF at end), and
16468  // if so need to process it
16469  EndOfFile = true;
16470  break;
16471  }
16472  AnsiString OneLine(TrainTimetableString);
16473  bool FinalCallTrue = true;
16474  while((Count == 0) && !TrainController->ProcessOneTimetableLine(0, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages,
16475  CheckLocationsExistInRailway)) // get rid of lines before the start time
16476  {
16477  TTBLFile.getline(TrainTimetableString, 10000, '\0');
16478  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
16479  {
16480  TTBLFile.close();
16481  throw Exception("Timetable FinalCall error - no start time on own line, Count = 0");
16482  }
16483  OneLine = AnsiString(TrainTimetableString);
16484  }
16485  // here when have accepted the start time
16486  if(Count == 0)
16487  {
16488  Count++; // increment past the start time
16489  TTBLFile.getline(TrainTimetableString, 10000, '\0'); // get next line after start time
16490  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
16491  {
16492  EndOfFile = true;
16493  OneLine = "";
16494  }
16495  else
16496  OneLine = AnsiString(TrainTimetableString);
16497  }
16498  if(!TrainController->ProcessOneTimetableLine(1, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages, CheckLocationsExistInRailway))
16499  {
16500  TTBLFile.close();
16501  throw Exception("Timetable FinalCall error in processing one timetable line, Count = " + AnsiString(Count));
16502  }
16503  if(EndOfFile && (Count < 2)) // Timetable must contain at least two relevant lines, one for start time and at least one train
16504  {
16505  TTBLFile.close();
16506  throw Exception("Timetable FinalCall error - too few or no relevant entries, Count = " + AnsiString(Count));
16507  }
16508  Count++;
16509  }
16510  TTBLFile.close();
16511  delete TrainTimetableString;
16512 // here when first pass actions completed successfully
16513  if(!TrainController->SecondPassActions(1, GiveMessages)) // Check for matching join/split HeadCodes, check increasing times & matching split/join
16514  // times, complete arrival & departure times for each TT line, check & complete train info for each type of start,
16515  // messages given in function if errors & vector cleared
16516  {
16517 // if(GiveMessages) ShowMessage("Timetable secondary integrity check failed");
16518 // above dropped in v2.4.0 as all called functions give own messages
16519  Utilities->CallLogPop(1665);
16520  return false;
16521  }
16522  Utilities->CallLogPop(1666);
16523  return true;
16524 }
16525 
16526 // ---------------------------------------------------------------------------
16527 
16528 bool TInterface::SessionFileIntegrityCheck(int Caller, AnsiString FileName)
16529 /* Here need to check as far as timetable, then go back and load the track, because the timetable compilation check
16530  relies on the track vector and map being in place. Won't affect the later load because the vector and map are cleared
16531  before loading.
16532 
16533  Although this appears cumbersome, I initially used tellg() & seekg() to reposition the file pointer without having to do
16534  all this backtracking. However after many problems I eventually found that tellg() sometimes returns false values,
16535  which cause problems when reloaded using seekg(). This must be a compiler problem, though I could find no mention of it
16536  in the CBuilder4 issues list or on the web. The full write-up is at the end of this unit.
16537 
16538  Also, with hindsight, I wish I had just saved and reloaded the timetable vectors rather than the text of the timetable. That
16539  would probably have been easier. To change it now though would cause compatibility problems with sessions created by earlier versions.
16540 */
16541 {
16542  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SessionFileIntegrityCheck," + FileName);
16543  std::ifstream InFile(FileName.c_str());
16544 // first pass as far as timetable
16545  int NumberOfActiveElements;
16546  bool GraphicsFollow = false;
16547 
16548  if(InFile.is_open())
16549  {
16551  // expected to be "***Interface***" for original version or "Version + : ***Interface***" for later releases + ExcessLCDownMins added as float after v2.2.0
16552  {
16553  InFile.close();
16554  Utilities->CallLogPop(1240);
16555  return false;
16556  }
16557  if(!CheckInterface(0, InFile))
16558  {
16559  InFile.close();
16560  Utilities->CallLogPop(1241);
16561  return false;
16562  }
16563  // check track elements
16564  if(!Utilities->CheckAndCompareFileString(InFile, "***Track***"))
16565  {
16566  InFile.close();
16567  Utilities->CallLogPop(1242);
16568  return false;
16569  }
16570  if(!Track->CheckTrackElementsInFile(2, NumberOfActiveElements, GraphicsFollow, InFile))
16571  {
16572  InFile.close();
16573  Utilities->CallLogPop(1243);
16574  return false;
16575  }
16576  if(InFile.fail())
16577  {
16578  InFile.close();
16579  Utilities->CallLogPop(1244);
16580  return false;
16581  }
16582  // check text elements
16583  if(!Utilities->CheckAndCompareFileString(InFile, "***Text***"))
16584  {
16585  InFile.close();
16586  Utilities->CallLogPop(1245);
16587  return false;
16588  }
16589  if(!TextHandler->CheckTextElementsInFile(1, InFile))
16590  {
16591  InFile.close();
16592  Utilities->CallLogPop(1246);
16593  return false;
16594  }
16595  if(InFile.fail())
16596  {
16597  InFile.close();
16598  Utilities->CallLogPop(1247);
16599  return false;
16600  }
16601  // check PrefDir elements
16602  if(!Utilities->CheckAndCompareFileString(InFile, "***PrefDirs***"))
16603  {
16604  InFile.close();
16605  Utilities->CallLogPop(1248);
16606  return false;
16607  }
16608  if(!EveryPrefDir->CheckOnePrefDir(1, NumberOfActiveElements, InFile))
16609  {
16610  InFile.close();
16611  Utilities->CallLogPop(1249);
16612  return false;
16613  }
16614  if(InFile.fail())
16615  {
16616  InFile.close();
16617  Utilities->CallLogPop(1250);
16618  return false;
16619  }
16620  // check graphics
16621  if(GraphicsFollow)
16622  {
16623  if(!Track->CheckUserGraphics(1, InFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
16624  {
16625  InFile.close();
16626  Utilities->CallLogPop(2187);
16627  return false;
16628  }
16629  if(InFile.fail())
16630  {
16631  InFile.close();
16632  Utilities->CallLogPop(2188);
16633  return false;
16634  }
16635  }
16636  // check routes
16637  if(!Utilities->CheckAndCompareFileString(InFile, "***Routes***"))
16638  {
16639  InFile.close();
16640  Utilities->CallLogPop(1251);
16641  return false;
16642  }
16643  if(!AllRoutes->CheckRoutes(0, NumberOfActiveElements, InFile))
16644  {
16645  InFile.close();
16646  Utilities->CallLogPop(1252);
16647  return false;
16648  }
16649  if(InFile.fail())
16650  {
16651  InFile.close();
16652  Utilities->CallLogPop(1253);
16653  return false;
16654  }
16655  // check LockedRoutes
16656  if(!Utilities->CheckAndCompareFileString(InFile, "***Locked routes***"))
16657  {
16658  InFile.close();
16659  Utilities->CallLogPop(1254);
16660  return false;
16661  }
16662  if(!TrainController->CheckSessionLockedRoutes(0, InFile))
16663  {
16664  InFile.close();
16665  Utilities->CallLogPop(1255);
16666  return false;
16667  }
16668  if(InFile.fail())
16669  {
16670  InFile.close();
16671  Utilities->CallLogPop(1256);
16672  return false;
16673  }
16674  // check ContinuationAutoSigs
16675  if(!Utilities->CheckAndCompareFileString(InFile, "***ContinuationAutoSigEntries***"))
16676  {
16677  InFile.close();
16678  Utilities->CallLogPop(1257);
16679  return false;
16680  }
16682  {
16683  InFile.close();
16684  Utilities->CallLogPop(1258);
16685  return false;
16686  }
16687  if(InFile.fail())
16688  {
16689  InFile.close();
16690  Utilities->CallLogPop(1259);
16691  return false;
16692  }
16693  // check BarriersDownVector, but ensure backwards compatibility with earlier files which don't have this section
16694  AnsiString TempString = Utilities->LoadFileString(InFile);
16695  if((TempString != "***BarriersDownVector***") && (TempString != "***Timetable***"))
16696  {
16697  InFile.close();
16698  Utilities->CallLogPop(1964);
16699  return false;
16700  }
16701  if(TempString == "***BarriersDownVector***")
16702  {
16703  if(!Track->CheckActiveLCVector(0, InFile))
16704  {
16705  InFile.close();
16706  Utilities->CallLogPop(1965);
16707  return false;
16708  }
16709  if(InFile.fail())
16710  {
16711  InFile.close();
16712  Utilities->CallLogPop(1966);
16713  return false;
16714  }
16715  if(!Utilities->CheckAndCompareFileString(InFile, "***Timetable***"))
16716  {
16717  InFile.close();
16718  Utilities->CallLogPop(1260);
16719  return false;
16720  }
16721  }
16722  // check timetable (marker string already checked immediately above)
16723  if(!CheckTimetableFromSessionFile(0, InFile))
16724  {
16725  InFile.close();
16726  Utilities->CallLogPop(1261);
16727  return false;
16728  }
16729  if(InFile.fail())
16730  {
16731  InFile.close();
16732  Utilities->CallLogPop(1262);
16733  return false;
16734  }
16735  }
16736  else
16737  {
16738  InFile.close();
16739  ShowMessage("Session file failed to open, unable to load session. Ensure that there is a folder named " + SESSION_DIR_NAME +
16740  " in the folder where the 'Railway.exe' program file resides");
16741  Utilities->CallLogPop(1263);
16742  return false;
16743  }
16744 
16745 // now ready for the 2nd pass for timetable loading and checking
16746  InFile.close();
16747  InFile.open(FileName.c_str());
16748  if(InFile.is_open())
16749  {
16751  {
16752  InFile.close();
16753  Utilities->CallLogPop(1264);
16754  return false;
16755  }
16756  if(!CheckInterface(1, InFile))
16757  {
16758  InFile.close();
16759  Utilities->CallLogPop(1265);
16760  return false;
16761  }
16762  // load track elements
16763  if(!Utilities->CheckAndCompareFileString(InFile, "***Track***"))
16764  {
16765  InFile.close();
16766  Utilities->CallLogPop(1266);
16767  return false;
16768  }
16769  bool GraphicsFollow = false;
16770  Track->LoadTrack(2, InFile, GraphicsFollow); // load the track this time
16771  if(InFile.fail())
16772  {
16773  InFile.close();
16774  Utilities->CallLogPop(1267);
16775  return false;
16776  }
16777  // check text elements
16778  if(!Utilities->CheckAndCompareFileString(InFile, "***Text***"))
16779  {
16780  InFile.close();
16781  Utilities->CallLogPop(1268);
16782  return false;
16783  }
16784  if(!TextHandler->CheckTextElementsInFile(2, InFile))
16785  {
16786  InFile.close();
16787  Utilities->CallLogPop(1269);
16788  return false;
16789  }
16790  if(InFile.fail())
16791  {
16792  InFile.close();
16793  Utilities->CallLogPop(1270);
16794  return false;
16795  }
16796  // check PrefDir elements
16797  if(!Utilities->CheckAndCompareFileString(InFile, "***PrefDirs***"))
16798  {
16799  InFile.close();
16800  Utilities->CallLogPop(1271);
16801  return false;
16802  }
16803  if(!EveryPrefDir->CheckOnePrefDir(2, NumberOfActiveElements, InFile))
16804  {
16805  InFile.close();
16806  Utilities->CallLogPop(1272);
16807  return false;
16808  }
16809  if(InFile.fail())
16810  {
16811  InFile.close();
16812  Utilities->CallLogPop(1273);
16813  return false;
16814  }
16815  // check graphics
16816  if(GraphicsFollow)
16817  {
16818  if(!Track->CheckUserGraphics(2, InFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
16819  {
16820  InFile.close();
16821  Utilities->CallLogPop(2189);
16822  return false;
16823  }
16824  if(InFile.fail())
16825  {
16826  InFile.close();
16827  Utilities->CallLogPop(2190);
16828  return false;
16829  }
16830  }
16831  // check routes
16832  if(!Utilities->CheckAndCompareFileString(InFile, "***Routes***"))
16833  {
16834  InFile.close();
16835  Utilities->CallLogPop(1274);
16836  return false;
16837  }
16838  if(!AllRoutes->CheckRoutes(1, NumberOfActiveElements, InFile))
16839  {
16840  InFile.close();
16841  Utilities->CallLogPop(1275);
16842  return false;
16843  }
16844  if(InFile.fail())
16845  {
16846  InFile.close();
16847  Utilities->CallLogPop(1276);
16848  return false;
16849  }
16850  // check LockedRoutes
16851  if(!Utilities->CheckAndCompareFileString(InFile, "***Locked routes***"))
16852  {
16853  InFile.close();
16854  Utilities->CallLogPop(1277);
16855  return false;
16856  }
16857  if(!TrainController->CheckSessionLockedRoutes(1, InFile))
16858  {
16859  InFile.close();
16860  Utilities->CallLogPop(1278);
16861  return false;
16862  }
16863  if(InFile.fail())
16864  {
16865  InFile.close();
16866  Utilities->CallLogPop(1279);
16867  return false;
16868  }
16869  // check ContinuationAutoSigs
16870  if(!Utilities->CheckAndCompareFileString(InFile, "***ContinuationAutoSigEntries***"))
16871  {
16872  InFile.close();
16873  Utilities->CallLogPop(1280);
16874  return false;
16875  }
16877  {
16878  InFile.close();
16879  Utilities->CallLogPop(1281);
16880  return false;
16881  }
16882  if(InFile.fail())
16883  {
16884  InFile.close();
16885  Utilities->CallLogPop(1282);
16886  return false;
16887  }
16888  // check BarriersDownVector, but ensure backwards compatibility with earlier files which don't have this section
16889  AnsiString TempString = Utilities->LoadFileString(InFile);
16890  if((TempString != "***BarriersDownVector***") && (TempString != "***Timetable***"))
16891  {
16892  InFile.close();
16893  Utilities->CallLogPop(1967);
16894  return false;
16895  }
16896  if(TempString == "***BarriersDownVector***")
16897  {
16898  if(!Track->CheckActiveLCVector(0, InFile))
16899  {
16900  InFile.close();
16901  Utilities->CallLogPop(1968);
16902  return false;
16903  }
16904  if(InFile.fail())
16905  {
16906  InFile.close();
16907  Utilities->CallLogPop(1969);
16908  return false;
16909  }
16910  if(!Utilities->CheckAndCompareFileString(InFile, "***Timetable***"))
16911  {
16912  InFile.close();
16913  Utilities->CallLogPop(1283);
16914  return false;
16915  }
16916  }
16917  // check timetable (marker string already checked)
16918  if(!LoadTimetableFromSessionFile(1, InFile))
16919  {
16920  InFile.close();
16921  Utilities->CallLogPop(1284);
16922  return false;
16923  }
16924  if(InFile.fail())
16925  {
16926  InFile.close();
16927  Utilities->CallLogPop(1285);
16928  return false;
16929  }
16930  // check timetable clock
16931  if(!Utilities->CheckAndCompareFileString(InFile, "***TimetableClock***"))
16932  {
16933  InFile.close();
16934  Utilities->CallLogPop(1286);
16935  return false;
16936  }
16937  if(!Utilities->CheckFileDouble(InFile))
16938  {
16939  InFile.close();
16940  Utilities->CallLogPop(1287);
16941  return false;
16942  }
16943  // check trains
16944  if(!Utilities->CheckAndCompareFileString(InFile, "***Trains***"))
16945  {
16946  InFile.close();
16947  Utilities->CallLogPop(1288);
16948  return false;
16949  }
16950  if(!TrainController->CheckSessionTrains(0, InFile))
16951  {
16952  InFile.close();
16953  Utilities->CallLogPop(1289);
16954  return false;
16955  }
16956  if(InFile.fail())
16957  {
16958  InFile.close();
16959  Utilities->CallLogPop(1290);
16960  return false;
16961  }
16962  if(!Utilities->CheckAndCompareFileString(InFile, "***Performance file***"))
16963  {
16964  InFile.close();
16965  Utilities->CallLogPop(1291);
16966  return false;
16967  }
16968  if(!CheckPerformanceFile(0, InFile))
16969  {
16970  InFile.close();
16971  Utilities->CallLogPop(1292);
16972  return false;
16973  }
16974  char TempChar;
16975  InFile.get(TempChar);
16976  while(!InFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '*'
16977  {
16978  InFile.get(TempChar);
16979  }
16980  if(!InFile.eof()) // additional checks needed
16981  {
16982  if(!Utilities->CheckFileString(InFile))
16983  {
16984  InFile.close();
16985  Utilities->CallLogPop(2198);
16986  return false;
16987  }
16988  if(!Utilities->CheckFileInt(InFile, 0, 1000000)) // TrainController->AvHoursIntValue
16989  {
16990  InFile.close();
16991  Utilities->CallLogPop(2199);
16992  return false;
16993  }
16994  if(!Utilities->CheckFileInt(InFile, 0, 1000000)) // number of train failures
16995  {
16996  InFile.close();
16997  Utilities->CallLogPop(2200);
16998  return false;
16999  }
17000  // now check any failed trains along with their OriginalPowerAtRail values
17001  Utilities->CheckFileString(InFile); // discard "***Failed Trains***"
17002  int IDVal;
17003  if(!Utilities->CheckAndReadFileInt(InFile, -1, 1000000, IDVal)) // train ID or -1 for no more failed trains,
17004  {
17005  InFile.close();
17006  Utilities->CallLogPop(2201);
17007  return false;
17008  }
17009  double PowerDouble;
17010  while(IDVal != -1)
17011  {
17012  Utilities->CheckFileDouble(InFile); // original power
17013  if(!Utilities->CheckAndReadFileInt(InFile, -1, 1000000, IDVal))
17014  {
17015  InFile.close();
17016  Utilities->CallLogPop(2202);
17017  return false;
17018  }
17019  }
17020  }
17021  InFile.close();
17022  }
17023  else
17024  {
17025  InFile.close();
17026  Utilities->CallLogPop(1293);
17027  return false;
17028  }
17029  Utilities->CallLogPop(1294);
17030  return true;
17031 }
17032 
17033 // ---------------------------------------------------------------------------
17034 
17035 void TInterface::LoadPerformanceFile(int Caller, std::ifstream &InFile)
17036  // Note that the file integrity has already been checked using CheckPerformanceFile
17037 {
17038  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPerformanceFile");
17039  AnsiString TempString = "", Line1 = "", Line2 = "", Line3 = "", Line4 = "", Line5 = "";
17040  char *Buffer = new char[1000];
17041  char TempChar;
17042 
17043  InFile.get(TempChar); // '\n'
17044  InFile.getline(Buffer, 1000);
17045  TempString = AnsiString(Buffer);
17046  while(TempString != "***End of performance file***")
17047  {
17048  PerformanceLogBox->Lines->Add(TempString);
17049  Utilities->PerformanceFile << TempString.c_str() << '\n';
17050  InFile.getline(Buffer, 1000);
17051  TempString = AnsiString(Buffer);
17052  }
17053  delete Buffer;
17054  Utilities->CallLogPop(1295);
17055 }
17056 
17057 // ---------------------------------------------------------------------------
17058 
17059 bool TInterface::CheckPerformanceFile(int Caller, std::ifstream &InFile)
17060 {
17061  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPerformanceFile");
17062  AnsiString TempString = "";
17063  char TempChar;
17064 
17065  InFile.get(TempChar);
17066  if(TempChar != '\n')
17067  {
17068  Utilities->CallLogPop(1296);
17069  return false;
17070  }
17071  if(!Utilities->CheckAndReadFileString(InFile, TempString))
17072  {
17073  Utilities->CallLogPop(1297);
17074  return false;
17075  }
17076  while(TempString != "***End of performance file***")
17077  {
17078  if(!Utilities->CheckAndReadFileString(InFile, TempString))
17079  {
17080  Utilities->CallLogPop(1298);
17081  return false;
17082  }
17083  }
17084  Utilities->CallLogPop(1299);
17085  return true;
17086 }
17087 
17088 // ---------------------------------------------------------------------------
17089 
17090 void TInterface::SavePerformanceFile(int Caller, std::ofstream &OutFile)
17091 {
17092  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePerformanceFile");
17093  AnsiString Text = PerformanceLogBox->Text;
17094 
17095  while(Text != "")
17096  {
17097  AnsiString OneLine = Text.SubString(1, Text.Pos('\x0D'));
17098  while((OneLine.Length() > 0) && OneLine[OneLine.Length()] < ' ')
17099  OneLine.SetLength(OneLine.Length() - 1); // get rid of trailing control characters
17100  Text = Text.SubString(Text.Pos('\x0D'), Text.Length());
17101  while((Text.Length() > 0) && Text[1] < ' ')
17102  Text = Text.SubString(2, (Text.Length() - 1)); // get rid of leading control characters
17103  OutFile << OneLine.c_str() << '\n';
17104  }
17105  Utilities->CallLogPop(1300);
17106 }
17107 
17108 // ---------------------------------------------------------------------------
17109 
17111 {
17112  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteButtonsInfoCaptionAndRouteNotStarted");
17113  if(EveryPrefDir->PrefDirSize() > 0)
17114  {
17115  if(AutoSigsFlag)
17116  {
17117  AutoSigsButton->Enabled = false;
17118  SigPrefButton->Enabled = true;
17119  UnrestrictedButton->Enabled = true;
17120  InfoPanel->Visible = true;
17121  if(Level2OperMode == PreStart)
17122  InfoPanel->Caption = "PRE-START: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
17123  else
17124  InfoPanel->Caption = "OPERATING: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
17125  InfoCaptionStore = InfoPanel->Caption;
17126  }
17127  else if(ConsecSignalsRoute) // PreferredRoute always same as ConsecSignalsRoute
17128  {
17129  AutoSigsButton->Enabled = true;
17130  SigPrefButton->Enabled = false;
17131  UnrestrictedButton->Enabled = true;
17132  InfoPanel->Visible = true;
17133  if(Level2OperMode == PreStart)
17134  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
17135  else
17136  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
17137  InfoCaptionStore = InfoPanel->Caption;
17138  }
17139  else
17140  {
17141  AutoSigsButton->Enabled = true;
17142  SigPrefButton->Enabled = true;
17143  UnrestrictedButton->Enabled = false;
17144  InfoPanel->Visible = true;
17145  if(Level2OperMode == PreStart)
17146  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
17147  else
17148  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
17149  InfoCaptionStore = InfoPanel->Caption;
17150  }
17151  }
17152  else
17153  {
17154  AutoSigsButton->Enabled = false;
17155  SigPrefButton->Enabled = false;
17156  UnrestrictedButton->Enabled = false;
17157  InfoPanel->Visible = true;
17158  if(Level2OperMode == PreStart)
17159  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
17160  else
17161  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
17162  InfoCaptionStore = InfoPanel->Caption;
17163  }
17165  {
17166  RouteCancelButton->Enabled = true;
17167  }
17168  else
17169  {
17170  RouteCancelButton->Enabled = false;
17171  }
17173  AutoRouteStartMarker->PlotOriginal(37, Display); // so start marker will replot if had selected start before pause & zoom
17176  Utilities->CallLogPop(1301);
17177 }
17178 
17179 // ---------------------------------------------------------------------------
17180 
17182 {
17183  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetPausedOrZoomedInfoCaption");
17184  if(Display->ZoomOutFlag)
17185  {
17186  InfoPanel->Visible = true;
17187  InfoPanel->Caption = "Left click screen to zoom in at that position";
17188  }
17189  else if(Level2OperMode == Paused)
17190  {
17191  InfoPanel->Visible = true;
17192  InfoPanel->Caption = "PAUSED: Railway state changes disabled";
17193  }
17194 // otherwise do nothing
17195  Utilities->CallLogPop(1302);
17196 }
17197 
17198 // ---------------------------------------------------------------------------
17199 
17201 {
17202  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DisableRouteButtons");
17203  RouteCancelButton->Enabled = false;
17204  AutoSigsButton->Enabled = false;
17205  SigPrefButton->Enabled = false;
17206  UnrestrictedButton->Enabled = false;
17207  Utilities->CallLogPop(1303);
17208 }
17209 
17210 // ---------------------------------------------------------------------------
17211 
17213  // no need for call logging as already failed
17214 {
17215 /*
17216  In order to reload as a session file:
17217 
17218  NB: Don't change it to a .txt file, as the '\0' characters [shown as a small square in wordpad] will be changed to spaces if it is subsequently saved
17219  strip out:-
17220 
17221  [since adding user graphics after prefdirs need to take this into account]
17222 
17223  up to but excluding ***Interface***
17224  from & including ***ConstructPrefDir PrefDirVector***
17225  to but excluding ***PrefDirs***
17226  if there is a single line ***UserGraphics*** delete it (won't be present if no graphics)
17227  from & including ***ConstructRoute PrefDirVector***
17228  to but excluding ***Routes***
17229  from & including ***ChangingLCVector*** to but excluding ***Timetable*** [if have ***No timetable loaded*** then can't use as a session file]
17230  from & including ***No editing timetable*** or ***Editing timetable - [title]***
17231  to but excluding ***TimetableClock***
17232  and save as a .ssn file.
17233 
17234  In order to load as a railway file:
17235 
17236  NB: Don't change it to a .txt file, as the '\0' characters will be changed to spaces if it is subsequently saved
17237 
17238  note or copy the version information at the top of the file
17239  copy the two numbers on rows 7 & 8 below ***Interface*** (i.e ***Interface*** = row 0) on their own lines immediately after the ***Track*** line (these become DisplayOffsetH & V)
17240  strip out up to but excluding ***Track*** - this is needed to keep the \0 entry at end of ***Track*** [shown as a small square in wordpad]
17241  add the version number either before or instead of ***Track***, ensuring that the \0 is retained
17242  the next line should contain the number of active elements - leave that in.
17243  strip out ***Text*** including the \0
17244  strip out from & including ***ConstructPrefDir PrefDirVector*** to & including ***PrefDirs*** (and the \0)
17245  strip out from & including ***ConstructRoute PrefDirVector*** to the end of the file
17246  rename as .dev or .rly file
17247 
17248  BUT - note that signals (and points, though they won't show) will be set as they were left. To reset to red, load a suitable timetable & select
17249  'Operate' then 'Exit operation'.
17250 */
17251 
17252 /*
17253  In order to extract a timetable:
17254 
17255  NB: Don't change it to a .txt file, as the '\0' characters will be changed to spaces if it is subsequently saved
17256 
17257  set wordwrap to window on
17258  strip out all to and including ***Timetable*** or ***Editing timetable.... depending which is to be saved
17259  ensure any text before start time ends with /0, otherwise don't need the \0
17260  strip out all after the final /0 immediately before ***End*** or ***End of timetable***, but ensure leave the final /0
17261  save as a .ttb file
17262 */
17263 
17264  Screen->Cursor = TCursor(-11); // Hourglass;
17265  AnsiString ErrorFileStr = CurDir + "\\errorlog.err";
17266  std::ofstream ErrorFile(ErrorFileStr.c_str());
17267 
17268  if(!(ErrorFile.fail()))
17269  {
17270 // save mouse position relative to mainscreen
17271  int ScreenX = Mouse->CursorPos.x - MainScreen->ClientOrigin.x;
17272  int ScreenY = Mouse->CursorPos.y - MainScreen->ClientOrigin.y;
17273  AnsiString MouseStr = "Posx: " + AnsiString(ScreenX) + "; Posy: " + AnsiString(ScreenY);
17274  Utilities->SaveFileString(ErrorFile, MouseStr);
17275  Utilities->SaveFileInt(ErrorFile, MissedTicks);
17276  Utilities->SaveFileInt(ErrorFile, TotalTicks);
17277 
17278 // save call stack
17279  Utilities->SaveFileString(ErrorFile, "***Call stack***");
17280  for(unsigned int x = 0; x < Utilities->CallLog.size(); x++)
17281  {
17282  AnsiString Item = Utilities->CallLog.at(x);
17283  ErrorFile << Item.c_str() << '\n';
17284  }
17285 // save event log
17286  Utilities->SaveFileString(ErrorFile, "***Event log***");
17287  for(unsigned int x = 0; x < Utilities->EventLog.size(); x++)
17288  {
17289  AnsiString Item = Utilities->EventLog.at(x);
17290  ErrorFile << Item.c_str() << '\n';
17291  }
17292 // save interface
17293  Utilities->SaveFileString(ErrorFile, "***Interface***");
17294  SaveInterface(1, ErrorFile);
17295 // save track elements
17296  Utilities->SaveFileString(ErrorFile, "***Track***");
17297  if(Track->UserGraphicVector.empty())
17298  {
17299  Track->SaveTrack(2, ErrorFile, false); // false for no graphics (**Active elements** saved as marker)
17300  }
17301  else
17302  {
17303  Track->SaveTrack(12, ErrorFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
17304  }
17305 // save text elements
17306  Utilities->SaveFileString(ErrorFile, "***Text***");
17307  TextHandler->SaveText(3, ErrorFile);
17308 // save ConstructPrefDir PrefDirVector elements
17309  Utilities->SaveFileString(ErrorFile, "***ConstructPrefDir PrefDirVector***");
17310  ConstructPrefDir->SavePrefDirVector(7, ErrorFile);
17311 // save ConstructPrefDir SearchVector elements
17312  Utilities->SaveFileString(ErrorFile, "***ConstructPrefDir SearchVector***");
17313  ConstructPrefDir->SaveSearchVector(0, ErrorFile);
17314 // save EveryPrefDir elements
17315  Utilities->SaveFileString(ErrorFile, "***PrefDirs***");
17316  EveryPrefDir->SavePrefDirVector(3, ErrorFile);
17317  if(!Track->UserGraphicVector.empty())
17318  {
17319  // save user graphics
17320  Utilities->SaveFileString(ErrorFile, "***UserGraphics***");
17321  Track->SaveUserGraphics(3, ErrorFile);
17322  }
17323 // save ConstructRoute PrefDirVector
17324  Utilities->SaveFileString(ErrorFile, "***ConstructRoute PrefDirVector***");
17325  ConstructRoute->SavePrefDirVector(4, ErrorFile);
17326 // save ConstructRoute SearchVector
17327  Utilities->SaveFileString(ErrorFile, "***ConstructRoute SearchVector***");
17328  ConstructRoute->SaveSearchVector(1, ErrorFile);
17329 // save AllRoutes
17330  Utilities->SaveFileString(ErrorFile, "***Routes***");
17331  AllRoutes->SaveRoutes(1, ErrorFile);
17332 // save LockedRoutes
17333  Utilities->SaveFileString(ErrorFile, "***Locked routes***");
17335 // save ContinuationAutoSigEntries
17336  Utilities->SaveFileString(ErrorFile, "***ContinuationAutoSigEntries***");
17338 // save BarriersDownVector
17339  Utilities->SaveFileString(ErrorFile, "***BarriersDownVector***");
17340  Track->SaveSessionBarriersDownVector(1, ErrorFile);
17341 // save ChangingLCVector
17342  Utilities->SaveFileString(ErrorFile, "***ChangingLCVector***");
17343  Track->SaveChangingLCVector(0, ErrorFile);
17344 // save loaded timetable
17345  if(TimetableTitle == "")
17346  Utilities->SaveFileString(ErrorFile, "***No timetable loaded***");
17347  else
17348  {
17349  Utilities->SaveFileString(ErrorFile, "***Timetable***");
17350  if(!(SaveTimetableToSessionFile(1, ErrorFile, ErrorFileStr)))
17351  {
17352  Utilities->SaveFileString(ErrorFile, "***Loaded timetable failed to save***");
17353  }
17354  }
17355 // save editing timetable
17356  if(CreateEditTTTitle == "")
17357  Utilities->SaveFileString(ErrorFile, "***No editing timetable***");
17358  else
17359  {
17360  Utilities->SaveFileString(ErrorFile, "***Editing timetable - " + CreateEditTTTitle + "***");
17361  if(!(SaveTimetableToErrorFile(1, ErrorFile, ErrorFileStr, CreateEditTTFileName)))
17362  {
17363  Utilities->SaveFileString(ErrorFile, "***Editing timetable failed to save***");
17364  }
17365  }
17366 // save TimetableClock
17367  Utilities->SaveFileString(ErrorFile, "***TimetableClock***");
17368  Utilities->SaveFileDouble(ErrorFile, double(TrainController->TTClockTime));
17369 // save trains
17370  Utilities->SaveFileString(ErrorFile, "***Trains***");
17371  TrainController->SaveSessionTrains(1, ErrorFile);
17372 // save performance file
17373  Utilities->SaveFileString(ErrorFile, "***Performance file***");
17374  SavePerformanceFile(1, ErrorFile);
17375  Utilities->SaveFileString(ErrorFile, "***End of performance file***");
17376 // addition at v2.4.1 to save TrainController->AvHoursIntValue + any future additions
17377  Utilities->SaveFileString(ErrorFile, "***Additions after v2.3.1***");
17380  Utilities->SaveFileString(ErrorFile, "***Failed Trains***");
17381  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
17382  {
17384  {
17387  }
17388  }
17389  Utilities->SaveFileInt(ErrorFile, -1); // marker for end of failed trains
17390  Utilities->SaveFileString(ErrorFile, "End of file at v2.4.1");
17391 // end of v2.4.1 addition
17392 
17393  ErrorFile.close();
17394  }
17395  else
17396  {
17397  TrainController->StopTTClockMessage(6, "Error file failed to open, error log won't be saved.");
17398  }
17399  Screen->Cursor = TCursor(-2); // Arrow
17400 }
17401 
17402 // ---------------------------------------------------------------------------
17403 
17404 void TInterface::SaveTempTimetableFile(int Caller, AnsiString InFileName)
17405  // the .ttb section is delimited by '\n' followed by "***End***"
17406  // first create a .ttb file in the working folder exactly like the original
17407 
17408  // Note: this type of file use failed when used to resave timetable.tmp from temp .ttb file, but changed that to avoid so many rapid
17409  // file actions in quick succession & been OK since then, but nevertheless keep the 10 retries before giving message to be on safe side
17410 {
17411  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTempTimetableFile");
17412  if((TempTTFileName != "") && FileExists(TempTTFileName))
17413  {
17414  DeleteFile(TempTTFileName);
17415  }
17416  int TempTTFileNumber = 0;
17417 
17418  while(FileExists(CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp"))
17419  {
17420  TempTTFileNumber++;
17421  }
17422  TempTTFileName = CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp";
17423  int InHandle = FileOpen(InFileName, fmOpenRead);
17424  int Count = 0;
17425 
17426  while(InHandle < 0) // sometimes fails, have 10 retries before giving message
17427  {
17428  InHandle = FileOpen(InFileName, fmOpenRead);
17429  Count++;
17430  Delay(2, 50); // 50mSec delay between tries
17431  if(Count > 10)
17432  {
17433  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
17434  Utilities->CallLogPop(1400);
17435  return;
17436  }
17437  }
17438  int OutHandle = FileCreate(TempTTFileName);
17439 
17440  Count = 0;
17441  while(OutHandle < 0) // sometimes fails, have 10 retries before giving message
17442  {
17443  OutHandle = FileCreate(TempTTFileName);
17444  Count++;
17445  Delay(3, 50); // 50mSec delay between tries
17446  if(Count > 10)
17447  {
17448  ShowMessage("Failed to save temporary timetable file, sessions can't be saved - try again, may only be a temporary problem");
17449  FileClose(InHandle);
17450  Utilities->CallLogPop(1401);
17451  return;
17452  }
17453  }
17454  int CountIn, CountOut;
17455  char *Buffer = new char[10000]; // can't use LoadFileString as that expects a '\0' delimiter
17456 
17457  while(true)
17458  {
17459  CountIn = FileRead(InHandle, Buffer, 10000);
17460  CountOut = FileWrite(OutHandle, Buffer, CountIn);
17461  if(CountOut != CountIn)
17462  {
17463  ShowMessage("Error in writing to the temporary timetable file, sessions can't be saved - try again, may only be a temporary problem");
17464  delete Buffer;
17465  FileClose(InHandle);
17466  FileClose(OutHandle);
17467  Utilities->CallLogPop(1402);
17468  return;
17469  }
17470  if(CountIn < 10000)
17471  break;
17472  }
17473  delete Buffer;
17474  FileClose(InHandle);
17475  FileClose(OutHandle);
17476  Utilities->CallLogPop(1403);
17477 }
17478 
17479 // ---------------------------------------------------------------------------
17480 
17481 void TInterface::SetTrackLengths(int Caller, int Distance, int SpeedLimit) // Distance & SpeedLimit are -1 for no change to that parameter
17482 /*
17483  Rules: Platforms are fixed length elements of 100m and aren't changed. Variable length elements can't be less than 20m.
17484  above changed in v2.4.0 to be variable as other track, but if <50m or >200m a warning is given
17485 
17486  Enter with DistanceVector containing the PrefDir to be set, Distance containing the required sum of all element lengths,
17487  and SpeedLimit containing the speed limit. If either of these is -1 (can be -1 separately) then no change is to be made to it.
17488  Return for an empty DistanceVector. Deal first with a single element in the vector, giving a message if there is a platform there.
17489  Now set exit link position (XLinkPos) value for the first element in DistanceVector by checking which link connects to the second
17490  element in the vector, and give a warning message if fail to find it. Now have to make two passes through the vector, firstly to
17491  sum the fixed lengths, count the number of variable length elements and set the speed limit, and secondly to set the lengths.
17492  Firstly store the first XLinkPos so don't have to recalculate it for the second pass. On the first pass examine each element,
17493  incrementing the variable element count or summing the fixed length count as go along, and setting the speed limits providing
17494  SpeedLimit isn't -1. If Distance was -1 then still go through but don't count anything, just set the speed limits. Recalculate
17495  the next XLinkPos for each succeeding element.
17496  After the first pass return if Distance was -1 as in that case have now finished. Otherwise check if the distance to be set is less than
17497  the minimum possible within the rules, and if so give a message and return. Also give a warning message if there aren't any variable length
17498  elements. Now enter the second pass. In this the length of each variable element is set to int(RemainingDistance/RemainingVarElements) and
17499  fixed length elements are ignored. After each variable length element is set the RemainingDistance and RemainingVarElements are recalculated
17500  ready for the next setting. In this way there is never more than 1 difference between any two variable length elements and the total
17501  distance sums exactly to the value required. A check is made after every variable length element has been set to see whether RemainingDistance
17502  and RemainingVarElements are zero, and if they don't reach zero together (which they should after the last variable length element has
17503  been set), an error message is given.
17504 */
17505 
17506 {
17507  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLengths," + AnsiString(Distance) + "," + AnsiString(SpeedLimit));
17508  bool FoundFlag;
17509 
17510 // ResetDistanceElements(4);
17511  if(ConstructPrefDir->PrefDirSize() == 0)
17512  {
17513  Utilities->CallLogPop(608);
17514  return;
17515  }
17516 // must have PrefDir size of at least 2
17517 
17518 // first pass to count number of variable length elements, sum fixed lengths & set speed limit
17519 // for version in v2.4.0 have no fixed length elements but leave code as is as much as possible
17520  int VarElements = 0; // FixedLength = 0; drop this in v2.4.0
17521  bool NamedLocPresent = false;
17522 
17523  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
17524  {
17525  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(167, x);
17526  TTrackElement & TE = Track->TrackElementAt(34, Track->GetVectorPositionFromTrackMap(28, PrefDirElement.HLoc, PrefDirElement.VLoc, FoundFlag));
17527  if(!FoundFlag)
17528  {
17529  throw Exception("Error - failed to find track element at " + AnsiString(TE.HLoc) + " & " + AnsiString(TE.VLoc) + " in SetLengths");
17530  }
17531  if((Distance != -1) && (!Track->IsPlatformOrNamedNonStationLocationPresent(2, TE.HLoc, TE.VLoc)))
17532  VarElements++;
17533  else if((Distance != -1) && (Track->IsPlatformOrNamedNonStationLocationPresent(3, TE.HLoc, TE.VLoc)))
17534  {
17535  VarElements++; // added in v2.4.0 for no fixed elements
17536  NamedLocPresent = true;
17537 // FixedLength+= DefaultTrackLength; dropped in v2.4.0 for no fixed elements
17538  }
17539 
17540  if((PrefDirElement.GetELinkPos() < 2) && (PrefDirElement.GetXLinkPos() < 2)) // could be points
17541  {
17542  if(SpeedLimit != -1)
17543  TE.SpeedLimit01 = SpeedLimit;
17544  }
17545  else
17546  {
17547  if(SpeedLimit != -1)
17548  TE.SpeedLimit23 = SpeedLimit;
17549  }
17550  }
17551  if(Distance == -1) // can't return before this as need to set speed limits
17552  {
17553  Utilities->CallLogPop(612);
17554  return;
17555  }
17556 
17557  if((NamedLocPresent) && (VarElements > 0) && ((Distance / VarElements) < 50)) // these two additions are for in v2.4.0
17558  {
17559  ShowMessage("Note: Named location elements are quite short. If they are too short the simulation might depart too far from reality.");
17560  }
17561 
17562  if((NamedLocPresent) && (VarElements > 0) && ((Distance / VarElements) > 200))
17563  {
17564  ShowMessage("Note: Named location elements are quite long. If they are too long the simulation might depart too far from reality.");
17565  }
17566 
17567 /* if(NamedLocPresent) as was
17568  {
17569  ShowMessage("Named location lengths won't be changed");
17570  }
17571 */
17572 
17573  if((VarElements * 20) > Distance) // removed '+ FixedLength'
17574  {
17575  ShowMessage("Required distance is less than the minimum, will set each element to the minimum (20m)");
17576  Distance = (VarElements * 20); // removed '+ FixedLength'
17577  }
17578  if(VarElements == 0)
17579  {
17580 // ShowMessage("Unable to set distance as all elements are of fixed length"); as was
17581  ShowMessage("No elements selected"); // probably don't need this but include for safety
17582  Utilities->CallLogPop(613);
17583  return;
17584  }
17585 
17586 // second pass, set variable lengths
17587  int RemainingDistance = Distance, RemainingVarElements = VarElements, NextLength = RemainingDistance / VarElements; // removed ' - FixedLength'
17588 
17589  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
17590  {
17591  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(168, x);
17592  TTrackElement & TE = Track->TrackElementAt(35, Track->GetVectorPositionFromTrackMap(29, PrefDirElement.HLoc, PrefDirElement.VLoc, FoundFlag));
17593 // if(!Track->IsPlatformOrNamedNonStationLocationPresent(4, TE.HLoc, TE.VLoc)) //variable lengths dropped in v2.4.0
17594 // {
17595  if(NextLength < 20)
17596  NextLength = 20; // added for safety
17597  if(TE.TrackType == Points)
17598  {
17599  if((PrefDirElement.GetELinkPos() == 1) || (PrefDirElement.GetXLinkPos() == 1))
17600  {
17601  TE.Length01 = NextLength;
17602  }
17603  else
17604  {
17605  TE.Length23 = NextLength;
17606  }
17607  }
17608  else
17609  {
17610  if(PrefDirElement.GetELinkPos() < 2)
17611  {
17612  TE.Length01 = NextLength;
17613  }
17614  else
17615  {
17616  TE.Length23 = NextLength;
17617  }
17618  }
17619  RemainingDistance -= NextLength;
17620  RemainingVarElements--;
17621  if(RemainingVarElements > 0)
17622  NextLength = RemainingDistance / RemainingVarElements;
17623  else
17624  NextLength = 20;
17625 
17626 /* removed these as using integer division & that sometimes problematic. None of these errors ever reported but be safe
17627  if((RemainingDistance == 0) && (RemainingVarElements != 0))
17628  {
17629  throw Exception("Error RemainingDistance == 0 & RemainingVarElements != 0");
17630  }
17631  if((RemainingDistance != 0) && (RemainingVarElements == 0))
17632  {
17633  throw Exception("Error RemainingDistance != 0 & RemainingVarElements == 0");
17634  }
17635 */
17636 // }
17637  }
17638  Utilities->CallLogPop(614);
17639 }
17640 
17641 // ---------------------------------------------------------------------------
17642 
17644 {
17645  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveAsSubroutine");
17647  ShowMessage("Nothing to save!");
17648  else
17649  {
17650  if(Track->IsReadyForOperation())
17651  {
17652  SaveRailwayDialog->Filter = "Development file (*.dev)|*.dev|Railway file (*.rly)|*.rly";
17653  }
17654  else
17655  SaveRailwayDialog->Filter = "Development file (*.dev)|*.dev";
17656  if(SaveRailwayDialog->Execute())
17657  {
17658  Screen->Cursor = TCursor(-11); // Hourglass;
17659  TrainController->LogEvent("Save " + SaveRailwayDialog->FileName);
17660  AnsiString Extension = "";
17661  if(SaveRailwayDialog->FileName.Length() > 2)
17662  {
17663  Extension = AnsiString(SaveRailwayDialog->FileName).SubString(AnsiString(SaveRailwayDialog->FileName).Length() - 2, 3).UpperCase();
17664  }
17665  if((Extension == "DEV") || (Track->IsReadyForOperation() && (Extension == "RLY")))
17666  {
17667  std::ofstream VecFile(AnsiString(SaveRailwayDialog->FileName).c_str());
17668  if(!(VecFile.fail()))
17669  {
17673  // save track elements
17674  if(Track->UserGraphicVector.empty())
17675  {
17676  Track->SaveTrack(1, VecFile, false); // false for no graphics (**Active elements** saved as marker)
17677  }
17678  else
17679  {
17680  Track->SaveTrack(13, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
17681  }
17682  // save text elements
17683  TextHandler->SaveText(1, VecFile);
17684  // save PrefDir elements
17685  EveryPrefDir->SavePrefDirVector(1, VecFile);
17686  if(!Track->UserGraphicVector.empty())
17687  {
17688  // save user graphics
17689  Track->SaveUserGraphics(4, VecFile);
17690  }
17691  VecFile.close();
17692  SavedFileName = SaveRailwayDialog->FileName; // includes the full PrefDir
17693  if(SavedFileName != "") // shouldn't be "" at this stage but leave in as a safeguard
17694  {
17695  char LastChar = SavedFileName[SavedFileName.Length()];
17696  if((LastChar == 'y') || (LastChar == 'Y'))
17697  {
17698  RlyFile = true;
17699  }
17700  else
17701  {
17702  RlyFile = false;
17703  }
17704  }
17705  else
17706  {
17707  RlyFile = false;
17708  }
17709  FileChangedFlag = false;
17710  for(int x = SaveRailwayDialog->FileName.Length(); x > 0; x--)
17711  {
17712  if(SaveRailwayDialog->FileName[x] == '\\')
17713  {
17714  RailwayTitle = SaveRailwayDialog->FileName.SubString(x + 1, SaveRailwayDialog->FileName.Length() - x - 4);
17715  // TimetableTitle = ""; leave this as is, no need to unload a tt just because saved railway
17716  SetCaption(7);
17717  break;
17718  }
17719  }
17720  Level1Mode = BaseMode;
17721  SetLevel1Mode(13); // to disable the save option
17722  } // if(!(VecFile.fail()))
17723  else
17724  ShowMessage("File open failed prior to save");
17725  } // else following if(!Track->IsReadyForOperation() && (Extension != "DEV"))
17726  else
17727  {
17728  ShowMessage("Can't save: extension must be either '.dev', or '.rly' with railway ready for operation");
17729  }
17730  Screen->Cursor = TCursor(-2); // Arrow
17731  } // else if(SaveRailwayDialog->Execute())
17732  else
17733  ShowMessage("File not saved");
17734  }
17735  Utilities->CallLogPop(1546);
17736 }
17737 
17738 // ---------------------------------------------------------------------------
17739 
17741 { // no need for caller or log as only setting values
17742  CutMenuItem->Visible = true;
17743  CopyMenuItem->Visible = true;
17744  FlipMenuItem->Visible = true;
17745  MirrorMenuItem->Visible = true;
17746  RotRightMenuItem->Visible = true;
17747  RotLeftMenuItem->Visible = true;
17748  RotateMenuItem->Visible = true;
17749  PasteMenuItem->Visible = true;
17750 // PasteWithAttributesMenuItem->Visible = true; //added at v2.2.0
17751  DeleteMenuItem->Visible = true;
17752  SelectLengthsMenuItem->Visible = true;
17753  ReselectMenuItem->Visible = true;
17754 
17755  CutMenuItem->Enabled = false;
17756  CopyMenuItem->Enabled = false;
17757  FlipMenuItem->Enabled = false;
17758  MirrorMenuItem->Enabled = false;
17759  RotRightMenuItem->Enabled = false;
17760  RotLeftMenuItem->Enabled = false;
17761  RotateMenuItem->Enabled = false;
17762  PasteMenuItem->Enabled = false;
17763 // PasteWithAttributesMenuItem->Enabled = false; //new at v2.2.0
17764  DeleteMenuItem->Enabled = false;
17765  SelectLengthsMenuItem->Enabled = false;
17766  if(SelectionValid)
17767  ReselectMenuItem->Enabled = true;
17768  else
17769  ReselectMenuItem->Enabled = false;
17770 
17771  SelectBiDirPrefDirsMenuItem->Visible = false;
17772  CancelSelectionMenuItem->Enabled = true;
17773  SelectMenuItem->Enabled = true;
17774 
17775  if(NoRailway())
17776  {
17777  EditMenu->Enabled = false;
17778  }
17779  else
17780  EditMenu->Enabled = true;
17781 }
17782 
17783 // ---------------------------------------------------------------------------
17784 
17786 { // no need for caller or log as only setting values
17787  EditMenu->Enabled = true;
17788 
17789  CutMenuItem->Visible = false;
17790  CopyMenuItem->Visible = false;
17791  FlipMenuItem->Visible = false;
17792  MirrorMenuItem->Visible = false;
17793  RotRightMenuItem->Visible = false;
17794  RotLeftMenuItem->Visible = false;
17795  RotateMenuItem->Visible = false;
17796  PasteMenuItem->Visible = false;
17797 // PasteWithAttributesMenuItem->Visible = false; //added at v2.2.0
17798  DeleteMenuItem->Visible = false;
17799  SelectLengthsMenuItem->Visible = false;
17800  ReselectMenuItem->Visible = false;
17801 
17802  SelectBiDirPrefDirsMenuItem->Visible = true;
17803  SelectBiDirPrefDirsMenuItem->Enabled = false;
17804  CancelSelectionMenuItem->Enabled = true;
17805  SelectMenuItem->Enabled = true;
17806 }
17807 
17808 // ---------------------------------------------------------------------------
17809 
17811 {
17812  return ((Track->NoActiveOrInactiveTrack(5)) && (TextHandler->TextVectorSize(8) == 0) && Track->UserGraphicVector.empty());
17813 }
17814 
17815 // ---------------------------------------------------------------------------
17816 
17818 {
17819  SelectRect.left = 0;
17820  SelectRect.right = 0;
17821  SelectRect.top = 0;
17822  SelectRect.bottom = 0;
17823 }
17824 
17825 // ---------------------------------------------------------------------------
17826 
17827 bool TInterface::EraseLocationNameText(int Caller, AnsiString Name, int &HPos, int &VPos)
17828 { // return position of erased name in HPos & VPos, return true for found & erased
17829  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationNameText," + Name);
17830  bool TextFound = false;
17831 
17832 // if(Track->LocationNameMultiMap.find(Name) == Track->LocationNameMultiMap.end()) {} //name not in LocationNameMultiMap, so don't erase from TextVector //condition dropped at v1.1.4 because of change in EnterLocationNames
17833 /* else */ if(TextHandler->FindText(0, Name, HPos, VPos))
17834  {
17835  if(TextHandler->TextErase(4, HPos, VPos))
17836  {;
17837  } // condition not used
17838  TextFound = true;
17839  }
17840  Utilities->CallLogPop(1956);
17841  return TextFound;
17842 }
17843 
17844 // ---------------------------------------------------------------------------
17845 
17846 void TInterface::AddLocationNameText(int Caller, AnsiString Name, int HPos, int VPos, bool UseEnteredPosition)
17847 {
17848  if(Name == "")
17849  {
17850  return;
17851  }
17852  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddLocationNameText," + Name + "," + AnsiString(HPos) + "," +
17853  AnsiString(VPos) + "," + AnsiString((short)UseEnteredPosition));
17854  int VPosHi, VPosLo, TextPosHi, TextPosLo;
17855  TFont *Font = Display->GetFont();
17856 
17857  if(!UseEnteredPosition)
17858  {
17859  if(!Track->FindHighestLowestAndLeftmostNamedElements(0, Name, VPosHi, VPosLo, HPos))
17860  {
17861  Utilities->CallLogPop(1561);
17862  return;
17863  }
17864  int Depth = abs(Font->Height); // Height may be negative - see C++Builder Help file
17865  TextPosHi = VPosHi + 20; // add depth of track element + 4 pixels
17866  TextPosLo = VPosLo - Depth - 4; // reduce by depth of font + 4 pixels
17867  int ScreenPosHi = (Display->DisplayOffsetV * 16) + 576;
17868  int ScreenPosLo = Display->DisplayOffsetV * 16;
17869  if(TextPosLo >= ScreenPosLo)
17870  VPos = TextPosLo; // if Lo value on screen then use that - displays above the location
17871  else if(TextPosHi < ScreenPosHi)
17872  VPos = TextPosHi;
17873  else
17874  VPos = ScreenPosLo + 288; // if location extends to or beyond height of screen the display in centre of screen
17875  }
17876  TTextItem TI(HPos, VPos, Name, Font);
17877 
17878  TI.Font = Font; // may have been changed in constructor when returned as reference
17879  TextHandler->EnterAndDisplayNewText(1, TI, HPos, VPos);
17880  Utilities->CallLogPop(1558);
17881 }
17882 
17883 // ---------------------------------------------------------------------------
17884 
17886 {
17887  try
17888  {
17889 /*
17890  ShowMessage(
17891  "Interface->Left + Interface->Width " + UnicodeString(Interface->Left + Interface->Width) +
17892  "\nInterface->Left + MainScreen->Left + MainScreen->Width " +
17893  UnicodeString(Interface->Left + MainScreen->Left + MainScreen->Width) +
17894  "\n\nMainScreen->Width " + UnicodeString(MainScreen->Width) +
17895  "\nMainScreen->Height " + UnicodeString(MainScreen->Height) +
17896  "\nMainScreen->Top " + UnicodeString(MainScreen->Top) +
17897  "\nMainScreen->Left " + UnicodeString(MainScreen->Left) +
17898  " Right " + UnicodeString(MainScreen->Width + MainScreen->Left) +
17899  "\n\nInterface->Width " + UnicodeString(Interface->Width) +
17900  "\nInterface->Left " + UnicodeString(Interface->Left) +
17901  "\nInterface->Top " + UnicodeString(Interface->Top) +
17902  "\n\nScreenRightButton->Left " + UnicodeString(ScreenRightButton->Left)
17903  );
17904 */
17905 /*
17906  for(unsigned int x=0; x<TrainController->TrainVector.size(); x++)
17907  {
17908  if((TrainController->TrainVectorAt(-1, x).HeadCode == "2K02") && (!TrainController->TrainVectorAt(-1, x).TrainOnContinuation(-1)))
17909  {
17910  TrainController->TrainVectorAt(-1, x).TrainFailurePending = true;
17911  }
17912  }
17913 */
17914 
17915 // throw Exception("Test error"); //generate an error file
17916 
17917 // ShowMessage("MissedTicks = " + AnsiString(MissedTicks) + "; TotalTicks = " + AnsiString(TotalTicks));
17918 
17919  }
17920  catch(const Exception &e)
17921  {
17922  ErrorLog(114, e.Message);
17923  }
17924 }
17925 
17926 // ---------------------------------------------------------------------------
17927 /*
17928  void TInterface::LoadNormalSignalGlyphs(int Caller) //changed - see below
17929  {
17930  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadNormalSignalGlyphs,");
17931  SpeedButton68->Glyph->LoadFromResourceName(0, "gl68"); SpeedButton69->Glyph->LoadFromResourceName(0, "gl69");
17932  SpeedButton70->Glyph->LoadFromResourceName(0, "gl70"); SpeedButton71->Glyph->LoadFromResourceName(0, "gl71");
17933  SpeedButton72->Glyph->LoadFromResourceName(0, "gl72"); SpeedButton73->Glyph->LoadFromResourceName(0, "gl73");
17934  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74"); SpeedButton75->Glyph->LoadFromResourceName(0, "gl75");
17935  Utilities->CallLogPop(**);
17936  }
17937 
17938  //---------------------------------------------------------------------------
17939 
17940  void TInterface::LoadGroundSignalGlyphs(int Caller) //changed - see below
17941  {
17942  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGroundSignalGlyphs,");
17943  SpeedButton68->Glyph->LoadFromResourceName(0, "bm68grounddblred"); SpeedButton69->Glyph->LoadFromResourceName(0, "bm69grounddblred");
17944  SpeedButton70->Glyph->LoadFromResourceName(0, "bm70grounddblred"); SpeedButton71->Glyph->LoadFromResourceName(0, "bm71grounddblred");
17945  SpeedButton72->Glyph->LoadFromResourceName(0, "bm72grounddblred"); SpeedButton73->Glyph->LoadFromResourceName(0, "gl73grounddblred");
17946  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74grounddblred"); SpeedButton75->Glyph->LoadFromResourceName(0, "bm75grounddblred");
17947  Utilities->CallLogPop(**);
17948  }
17949 */
17950 // ---------------------------------------------------------------------------
17951 void TInterface::LoadNormalSignalGlyphs(int Caller) // changed from the above at v2.3.0 so the signal glyphs change hands
17952 {
17953  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadNormalSignalGlyphs,");
17962  Utilities->CallLogPop(1871);
17963 }
17964 
17965 // ---------------------------------------------------------------------------
17966 
17967 void TInterface::LoadGroundSignalGlyphs(int Caller) // changed from the above at v2.3.0 so the signal glyphs change hands
17968 {
17969  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGroundSignalGlyphs,");
17978  Utilities->CallLogPop(1872);
17979 }
17980 
17981 // ---------------------------------------------------------------------------
17982 
17983 void TInterface::UpdateOperatorActionPanel(int Caller) // new at v2.2.0
17984  // limit it to 20 entries max
17985 {
17986  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UpdateOperatorActionPanel");
17988  {
17989  OAListBox->Clear();
17990  }
17992  // new at v2.2.0
17993  {
17994  Utilities->CallLogPop(2092);
17995  return;
17996  }
17997  AnsiString OpTimeToActDisplay;
17998  AnsiString OpTimeToActString;
17999  AnsiString HeadCode;
18000  float OpTimeToActFloat;
18001  TTrainController::THCandTrainPosParam HCandTrainPosParam;
18002 
18005  {
18006  if(OAListBox->Items->Count >= 20)
18007  {
18008  break;
18009  }
18010  OpTimeToActFloat = TrainController->OpTimeToActMultiMapIterator->first;
18011  HCandTrainPosParam = TrainController->OpTimeToActMultiMapIterator->second;
18012  HeadCode = HCandTrainPosParam.first;
18013  if(OpTimeToActFloat < 0.25) // 15 secs estimated
18014  {
18015  OpTimeToActString = "NOW";
18016  }
18017  else if(OpTimeToActFloat < 1)
18018  {
18019  OpTimeToActString = "<1";
18020  }
18021  else
18022  {
18023  OpTimeToActString = AnsiString(floor(OpTimeToActFloat));
18024  }
18025  if(OpTimeToActFloat < 60)
18026  {
18027  OpTimeToActDisplay = HeadCode + AnsiString('\t') + OpTimeToActString;
18028  OAListBox->Items->Add(OpTimeToActDisplay); // original
18029  }
18031  }
18032  Utilities->CallLogPop(2093);
18033 }
18034 
18035 // ---------------------------------------------------------------------------
18036 
18037 void TInterface::LoadUserGraphic(int Caller) // new at v2.4.0
18038 {
18039  try
18040  {
18041  TrainController->LogEvent("LoadUserGraphic");
18042  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadUserGraphic");
18044  if(LoadUserGraphicDialog->Execute())
18045  {
18046  TrainController->LogEvent("LoadUserGraphic " + LoadUserGraphicDialog->FileName);
18047  SelectedGraphicFileName = AnsiString(LoadUserGraphicDialog->FileName); // SelectedGraphicFileName is a class member
18049  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
18050  if(UGMIt == Track->UserGraphicMap.end()) // i.e. there isn't an entry for that filename so insert one, else take no action
18051  {
18052  UGME.first = SelectedGraphicFileName;
18053  TPicture *PicPtr = new TPicture;
18054  PicPtr->LoadFromFile(SelectedGraphicFileName);
18055  UGME.second = PicPtr;
18056  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
18057  {
18058  throw Exception("Map Insertion Error 1 - UserGraphicMap insertion failure for " + SelectedGraphicFileName);
18059  }
18060  }
18062  SetLevel2TrackMode(65);
18063  }
18064  Utilities->CallLogPop(2191);
18065  }
18066  catch(const EInvalidGraphic &e)
18067  {
18068  ShowMessage(
18069  "Incorrect file format, the file can't be loaded.\nEnsure that the file you want is a valid graphic file with extension .bmp, .gif, .jpg, or .png");
18070  }
18071  catch(const Exception &e)
18072  {
18073  ErrorLog(215, e.Message);
18074  }
18075 }
18076 
18077 // ---------------------------------------------------------------------------
18078 /*
18079  Problems with ifstream reading (see 'SessionFileIntegrityCheck(AnsiString FileName)' above):-
18080 
18081  These problems were with Borland C++Builder 4.
18082 
18083  The functions saved in OldFiles\Backups220809Duringifstream testing were used for testing the odd behaviour where the
18084  ifstream pointer gave different characters using get() and getline(), when reading the timetable entries in the session
18085  file for 20/08/09 at 18:45 (saved). All was well until point 48677 in the session file, when for some reason the
18086  getline(0 & get(0 gave different results. Many earlier timetable strings had been read OK before that, and it wasn't
18087  clear what was special about this particular string.
18088  Later more detailed study found that on reading the string beginning at point 48605 (i.e. the one earlier than above),
18089  within function CheckNoNewLineAtStartNonZeroTerminatedFileString the file pointer (using tellg()) reduced from 48606 to
18090  48604 after reading the 'F' character. Thereafter characters were read correctly but the pointer remained 2 too low.
18091  This is thought to be a flaw in the compiler.
18092  Later again additional tellg()s and a seekg()s were included in CheckNoNewLineAtStartNonZeroTerminatedFileString, and
18093  though these should have had no effect they somehow caused the next getline() within CheckTimetableFromSessionFile to
18094  read a null, even though the pointer had been reset to its value before the call to
18095  CheckNoNewLineAtStartNonZeroTerminatedFileString. Again this seems to be a flaw in the compiler, where the pointer
18096  that is indicated by tellg and the true pointer within the system can be different.
18097  Tried the old c++ stream library to see if that worked but it was exactly the same. Probably because the same code is
18098  used for both with the new library just defined within the std namespace.
18099  Success!! Traced to the putback function failing. It (apparently) can't be used if the file pointer has been altered
18100  after the last read that is to be put back. Corrected that & the most recent session file checked out & loaded OK.
18101  (note - don't need the ifstream file to be open in output mode for the putback to work)
18102  But: the earlier file - 18:45 as above - still fails to advance the file pointer in the middle of checking the
18103  timetable, it sticks at position 48601. This position points to 'r' in 'Frh' just before a newline. Also the file
18104  integrity is OK up to and after this sticking point. Oddly though the loading function works fine (i.e. by bypassing
18105  the integrity check function), though the timetable isn't read directly, it is copied to a new stand-alone timetable
18106  file and that read by the program.
18107  Created a new version of CheckNoNewLineAtStartNonZeroTerminatedFileString with 'New' at end, & got rid of all the
18108  internal digressions & getlines. This passed the earlier sticking point, but stuck later at 48677, i.e. the 'h' from
18109  'Frh' at the end of the entry following that for the earlier sticking point. Here
18110  CheckNoNewLineAtStartNonZeroTerminatedFileStringNew works fine, with end pointer correctly set at 48680, i.e. after the
18111  newline, but the subsequent getline() function, although it retrieves the line correctly, the file pointer is set to
18112  48677, i.e. before the newline, so getline seems to fail to extract the newline character. Still to check - why doesn't
18113  CheckNoNewLineAtStartNonZeroTerminatedFileStringNew see 'h' instead of '0' in the subsequent read? If it did the two
18114  would tally, though would still be wrong.
18115  Further investigation:- CheckNoNewLineAtStartNonZeroTerminatedFileStringNew doesn't seem to recognize the file pointer
18116  as set by seekg at 48677. It continues to read at the point it left off earlier, whereas getline() does read at 48677
18117  & recovers 'h'. Continuing to apply getline() after the above effect it is found that it doesn't extract newlines after
18118  reading further lines, but extracts them when read alone i.e. it reads a line then a null in succession, although the
18119  lines are only separated by single newline characters.
18120 
18121  Need to check:
18122  1. Does the file read correctly if only get() functions used without getline() and without resetting the file pointer?
18123  2. Does the file read correctly if only getline() functions used without get() and without resetting the file pointer?
18124  3. Does the file read correctly if get() functions alternated with getline() but without resetting the file pointer?
18125 
18126  For 1: Still goes wrong at usual place, reads 'h' at the same point. Try not resetting the file pointer with seekg.
18127  Tried this - got past the earlier point but failed later with a reduction in file pointer after a character read. In
18128  fact the reduction was by 40 bytes for reading a single comma! Try without any tellg's - yes, that got past all the
18129  timetable OK. So, works OK with just get() providing no tellg's (& no seekg's).
18130 
18131  For 2: Works OK using getline().
18132 
18133  For 3: Gets to end of timetable OK but the next tellg gives a wrong value. Check if using getline() alone gives a
18134  wrong tellg. Tried getline() alone, reached end of TT as before, but gave the same wrong file pos on using tellg.
18135  Try continuing to see if works OK in spite of tellg giving wrong result. Yes it works OK. Hence the problem seems to
18136  be tellg, which sometimes returns wrong results, and they corrupt things when used in seekg.
18137 
18138  Overall conclusion: Avoid all tellg's & seekg's. If need to reset a file position then close and reopen it.
18139 */
18140 
18141 // ---------------------------------------------------------------------------
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:15596
TInterface::SpeedButton59
TSpeedButton * SpeedButton59
Definition: InterfaceUnit.h:540
TInterface::CopyTTEntryButtonClick
void __fastcall CopyTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3525
TInterface::CtrlKey
bool CtrlKey
true when the CTRL key is pressed (used for small movements of the screen)
Definition: InterfaceUnit.h:937
TInterface::MTBFEditBox
TEdit * MTBFEditBox
Definition: InterfaceUnit.h:458
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:9712
TInterface::ScreenLeftButtonClick
void __fastcall ScreenLeftButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8055
TInterface::ExitMenuItem
TMenuItem * ExitMenuItem
Definition: InterfaceUnit.h:394
TTrain::AllowedToPassRedSignal
bool AllowedToPassRedSignal
set when train has been called on, or when under signaller control and instructed to pass a red signa...
Definition: TrainUnit.h:339
TInterface::TextMoveVPos
int TextMoveVPos
used to store the original text 'H' & 'V' positions for use during text moving
Definition: InterfaceUnit.h:1034
TInterface::OperMode
@ OperMode
Definition: InterfaceUnit.h:821
TTrain::ZeroPowerNoNewShuttleFromNonRepeatMessage
bool ZeroPowerNoNewShuttleFromNonRepeatMessage
Definition: TrainUnit.h:306
TInterface::SpeedButton140
TSpeedButton * SpeedButton140
Definition: InterfaceUnit.h:621
TTrain::ZeroPowerNoNewServiceMessage
bool ZeroPowerNoNewServiceMessage
Definition: TrainUnit.h:305
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:9683
TInterface::AddPrefDirButton
TBitBtn * AddPrefDirButton
Definition: InterfaceUnit.h:115
TInterface::RemoveTrainMenuItem
TMenuItem * RemoveTrainMenuItem
Definition: InterfaceUnit.h:444
TInterface::LocationNamesSetImage
TImage * LocationNamesSetImage
Definition: InterfaceUnit.h:257
TInterface::SpeedLimitBox
TEdit * SpeedLimitBox
distance/speed setting edit box that accepts speed limits
Definition: InterfaceUnit.h:91
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TInterface::SaveImageAndGridMenuItemClick
void __fastcall SaveImageAndGridMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2514
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:80
TTrainController
Handles all train and timetable activities, only one object created.
Definition: TrainUnit.h:628
TInterface::FloatingInfoMenu
TMenuItem * FloatingInfoMenu
Definition: InterfaceUnit.h:420
TInterface::SpeedButton34
TSpeedButton * SpeedButton34
Definition: InterfaceUnit.h:515
TInterface::CallingOnButton
TSpeedButton * CallingOnButton
Definition: InterfaceUnit.h:204
TInterface::BuildTrainDataVectorForValidateFile
bool BuildTrainDataVectorForValidateFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway)
Check the integrity of a stored timetable file (either as a stand alone file or within a session file...
Definition: InterfaceUnit.cpp:16455
TInterface::SpeedButton42
TSpeedButton * SpeedButton42
Definition: InterfaceUnit.h:523
TInterface::SelectBitmapMouseLocX
int SelectBitmapMouseLocX
when flag SelectPickedUp is set to true (see above - to allow a selected screen area to move during M...
Definition: InterfaceUnit.h:1010
TInterface::PrefDirPanel
TPanel * PrefDirPanel
'Set preferred directions' panel
Definition: InterfaceUnit.h:338
TInterface::PrefDirPanelLabel
TLabel * PrefDirPanelLabel
label to the left of PrefDirPanel
Definition: InterfaceUnit.h:284
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:11167
TInterface::MTBFEditBoxKeyUp
void __fastcall MTBFEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11814
TInterface::TrackMode
@ TrackMode
Definition: InterfaceUnit.h:821
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:12256
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1570
TInterface::SaveSessionButton
TBitBtn * SaveSessionButton
Definition: InterfaceUnit.h:200
TInterface::TTLabel2
TLabel * TTLabel2
Definition: InterfaceUnit.h:319
TInterface::TTClockx1ButtonClick
void __fastcall TTClockx1ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11417
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:181
TInterface::LengthConversionPanel
TPanel * LengthConversionPanel
Definition: InterfaceUnit.h:104
TInterface::SpeedButton143
TSpeedButton * SpeedButton143
Definition: InterfaceUnit.h:624
TInterface::ChangeDirectionMenuItem
TMenuItem * ChangeDirectionMenuItem
Definition: InterfaceUnit.h:439
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:6317
TTrain::MidEntryPos
int MidEntryPos
Definition: TrainUnit.h:327
TTrainController::PwrHigh
bool PwrHigh
Definition: TrainUnit.h:713
TInterface::StepForwardMenuItem
TMenuItem * StepForwardMenuItem
Definition: InterfaceUnit.h:442
TTrack::SelectGraphicVector
TUserGraphicVector SelectGraphicVector
Definition: TrackUnit.h:700
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:89
SignallerMoveForwards
@ SignallerMoveForwards
Definition: TrainUnit.h:50
TInterface::SignallerControlStopMenuItem
TMenuItem * SignallerControlStopMenuItem
Definition: InterfaceUnit.h:443
TRailGraphics::ConvertSignalsToOppositeHand
void ConvertSignalsToOppositeHand(int Caller)
Converts all signal graphics to opposite hand new at v2.3.0.
Definition: GraphicUnit.cpp:4264
TInterface::FormResize
void __fastcall FormResize(TObject *Sender)
Definition: InterfaceUnit.cpp:11668
TInterface::SpeedButton70
TSpeedButton * SpeedButton70
Definition: InterfaceUnit.h:551
TInterface::SpeedButton144
TSpeedButton * SpeedButton144
Definition: InterfaceUnit.h:625
TInterface::SpeedButton32
TSpeedButton * SpeedButton32
Definition: InterfaceUnit.h:513
TInterface::SaveTTAsButtonClick
void __fastcall SaveTTAsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3982
TInterface::SelectBitmapHLoc
int SelectBitmapHLoc
the original (prior to moving & after finished moving) HLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1008
TInterface::OperatorActionButton
TBitBtn * OperatorActionButton
Definition: InterfaceUnit.h:201
TInterface::DistanceKey
TImage * DistanceKey
information panel displayed when setting distances & speed limits
Definition: InterfaceUnit.h:247
AboutUnit.h
Arrive
@ Arrive
Definition: TrainUnit.h:49
TInterface::OperatorActionPanelDragStartX
int OperatorActionPanelDragStartX
mouse 'X' position when the OperatorActionPanel begins to be dragged
Definition: InterfaceUnit.h:996
TInterface::SpeedButton54
TSpeedButton * SpeedButton54
Definition: InterfaceUnit.h:535
TInterface::StartWholeRailwayMoveVPos
int StartWholeRailwayMoveVPos
mouse Y position when start to move the whole railway
Definition: InterfaceUnit.h:1020
TTrain::ZeroPowerNoCDTMessage
bool ZeroPowerNoCDTMessage
Definition: TrainUnit.h:304
TTrain::CallingOnFlag
bool CallingOnFlag
calling on permitted
Definition: TrainUnit.h:345
TInterface::UnrestrictedButton
TBitBtn * UnrestrictedButton
Definition: InterfaceUnit.h:196
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:701
TRailGraphics::SpeedBut72NormBlackGlyph
Graphics::TBitmap * SpeedBut72NormBlackGlyph
Definition: GraphicUnit.h:1041
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:11207
TInterface::ExportTTMenuItemClick
void __fastcall ExportTTMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2921
TInterface::CancelSelectionMenuItemClick
void __fastcall CancelSelectionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9320
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3543
TInterface::PERFLOG_DIR_NAME
static const UnicodeString PERFLOG_DIR_NAME
Definition: InterfaceUnit.h:834
TInterface::WholeRailwayMoving
bool WholeRailwayMoving
true when moving the railway with the mouse, new at v2.1.0
Definition: InterfaceUnit.h:965
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:13671
TInterface::TextFoundFlag
bool TextFoundFlag
indicates that a text item has been found when clicking on a build screen during 'AddText' or 'MoveTe...
Definition: InterfaceUnit.h:947
TInterface::DisableRouteButtons
void DisableRouteButtons(int Caller)
Called during operation whenever the route type buttons need to be disabled, e.g. when paused.
Definition: InterfaceUnit.cpp:17200
TInterface::OperateRailwayMenuItemClick
void __fastcall OperateRailwayMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1933
TInterface::DerailImage
TImage * DerailImage
Definition: InterfaceUnit.h:243
TTrain::MaxRunningSpeed
double MaxRunningSpeed
the current maximum train running speed
Definition: TrainUnit.h:383
TInterface::TTLabel3
TLabel * TTLabel3
Definition: InterfaceUnit.h:320
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:684
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:288
TRailGraphics::SpeedBut75NormBlackGlyph
Graphics::TBitmap * SpeedBut75NormBlackGlyph
Definition: GraphicUnit.h:1044
RestoreTimetableControl
@ RestoreTimetableControl
Definition: TrainUnit.h:50
TInterface::TTSelectedEntry
AnsiString TTSelectedEntry
used to record the current timetable entry when changing to AZ order or back to original order
Definition: InterfaceUnit.h:890
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:47
TAllRoutes::AutoSigsRoute
@ AutoSigsRoute
Definition: TrackUnit.h:1500
TInterface::SpeedButton19
TSpeedButton * SpeedButton19
Definition: InterfaceUnit.h:500
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5057
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5084
TActionVectorEntry::LocationType
TTimetableLocationType LocationType
indicates where the train is when the relevant action occurs
Definition: TrainUnit.h:112
TInterface::MasterClockTimer
void __fastcall MasterClockTimer(TObject *Sender)
Definition: InterfaceUnit.cpp:7521
TTrack::GapFlashGreenPosition
int GapFlashGreenPosition
Definition: TrackUnit.h:668
TInterface::MainScreen
TImage * MainScreen
the railway display screen
Definition: InterfaceUnit.h:264
TInterface::SpeedButton67
TSpeedButton * SpeedButton67
Definition: InterfaceUnit.h:548
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:65
TInterface::CutMenuItem
TMenuItem * CutMenuItem
Definition: InterfaceUnit.h:409
TInterface::SpeedButton120
TSpeedButton * SpeedButton120
Definition: InterfaceUnit.h:601
TInterface::LCResetCounter
unsigned int LCResetCounter
count up to 20 then resets - to check LCs & raise barriers if no route & no train present
Definition: InterfaceUnit.h:984
TInterface::BlueBgndMenuItem
TMenuItem * BlueBgndMenuItem
Definition: InterfaceUnit.h:404
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1644
TInterface::TTLabel1
TLabel * TTLabel1
Definition: InterfaceUnit.h:318
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:8754
TInterface::ResetChangedFileDataAndCaption
void ResetChangedFileDataAndCaption(int Caller, bool NonPrefDirChangesMade)
Called whenever the railway is changed to deal with title displays (loaded railway and timetable) and...
Definition: InterfaceUnit.cpp:15309
TTrain::MaxBrakeRate
double MaxBrakeRate
the maximum brake rate that the train can achieve
Definition: TrainUnit.h:387
TInterface::SpeedButton52
TSpeedButton * SpeedButton52
Definition: InterfaceUnit.h:533
TInterface::IMAGE_DIR_NAME
static const UnicodeString IMAGE_DIR_NAME
Definition: InterfaceUnit.h:836
TInterface::ShowPerformancePanel
bool ShowPerformancePanel
true when the 'show performance panel' button has been clicked during operation
Definition: InterfaceUnit.h:941
TInterface::LoadSessionDialog
TOpenDialog * LoadSessionDialog
Definition: InterfaceUnit.h:466
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TInterface::OutputLog10MouseDown
void __fastcall OutputLog10MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10758
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:522
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2448
TInterface::SpeedButton116
TSpeedButton * SpeedButton116
Definition: InterfaceUnit.h:597
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5213
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:148
TTrain::MidExitPos
int MidExitPos
Definition: TrainUnit.h:327
TInterface::NewSelectBitmapVLoc
int NewSelectBitmapVLoc
as above for VLoc
Definition: InterfaceUnit.h:994
TInterface::MoveTextOrGraphic
@ MoveTextOrGraphic
Definition: InterfaceUnit.h:851
TInterface::ScreenGridButton
TBitBtn * ScreenGridButton
Definition: InterfaceUnit.h:71
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:6960
TInterface::EditMenu
TMenuItem * EditMenu
Definition: InterfaceUnit.h:406
TTrain::TrainFailed
bool TrainFailed
added at v2.4.0 to indicate failure
Definition: TrainUnit.h:369
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:383
DisplayUnit.h
TInterface::ResetSelectRect
void ResetSelectRect()
SelectRect is the rectangle selected via the 'Edit'menu, and this function sets left,...
Definition: InterfaceUnit.cpp:17817
TInterface::TTLabel9
TLabel * TTLabel9
Definition: InterfaceUnit.h:326
TTrain::ZeroPowerNoFrontSplitMessage
bool ZeroPowerNoFrontSplitMessage
Definition: TrainUnit.h:300
TTrainController::SPADWarning
bool SPADWarning
Definition: TrainUnit.h:702
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:10964
TInterface::TrackNotLinkedImage
TImage * TrackNotLinkedImage
Definition: InterfaceUnit.h:254
TTrain::DepartureTimeSet
bool DepartureTimeSet
set when stopped at a location and the next action is departure (set in UpdateTrain when ReleaseTime ...
Definition: TrainUnit.h:347
TInterface::WarningHover
bool WarningHover
true when mouse hovers over warning messages during operation - to prevent clicking while changing
Definition: InterfaceUnit.h:963
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:6463
TInterface::SaveTTAsButton
TButton * SaveTTAsButton
Definition: InterfaceUnit.h:145
TInterface::ZoomButtonClick
void __fastcall ZoomButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8292
TInterface::SpeedButton90
TSpeedButton * SpeedButton90
Definition: InterfaceUnit.h:571
TTrain::LagElement
int LagElement
Definition: TrainUnit.h:327
TTrack::GetLocationName
AnsiString GetLocationName(unsigned int InactiveTrackVectorPosition)
Return location name for a given inactive track vector position.
Definition: TrackUnit.h:715
TTrainController::BufferAttentionWarning
bool BufferAttentionWarning
Definition: TrainUnit.h:702
TInterface::ExitTrackButtonClick
void __fastcall ExitTrackButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1624
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:8481
TInterface::SpeedButton135
TSpeedButton * SpeedButton135
Definition: InterfaceUnit.h:616
TInterface::SpeedButton111
TSpeedButton * SpeedButton111
Definition: InterfaceUnit.h:592
TInterface::RouteCancelFlag
bool RouteCancelFlag
true when route cancel button pressed, enables a right mouse click to cancel a route if in an appropr...
Definition: InterfaceUnit.h:925
TTextHandler::LoadText
void LoadText(int Caller, std::ifstream &VecFile)
load the railway's text from VecFile
Definition: TextUnit.cpp:275
TInterface::SpeedToggleButton2Click
void __fastcall SpeedToggleButton2Click(TObject *Sender)
Definition: InterfaceUnit.cpp:10945
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:12057
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:13794
TInterface::LoadNormalSignalGlyphs
void LoadNormalSignalGlyphs(int Caller)
In trackbuild display normal signal types on signal buttons.
Definition: InterfaceUnit.cpp:17951
TInterface::MainScreenMouseDown3
void MainScreenMouseDown3(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
Called when mouse button clicked in zoom-out mode.
Definition: InterfaceUnit.cpp:6878
TInterface::TTLabel11
TLabel * TTLabel11
Definition: InterfaceUnit.h:327
TInterface::CancelTTEntryButton
TButton * CancelTTEntryButton
Definition: InterfaceUnit.h:136
TInterface::SpeedButton8
TSpeedButton * SpeedButton8
Definition: InterfaceUnit.h:489
TInterface::UserGraphicVectorNumber
int UserGraphicVectorNumber
used to store a single item of user graphics
Definition: InterfaceUnit.h:1036
TInterface::PreviousTTEntryButton
TButton * PreviousTTEntryButton
Definition: InterfaceUnit.h:127
TInterface::TrackElementPanel
TPanel * TrackElementPanel
panel containing the track/location/parapet element buttons
Definition: InterfaceUnit.h:355
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:16393
TInterface::SelectionValid
bool SelectionValid
true when an area of screen has been selected via the 'Edit' & 'Select' or 'Reselect' menu items
Definition: InterfaceUnit.h:931
TDisplay::InvertElement
void InvertElement(int Caller, int HPos, int VPos)
Definition: DisplayUnit.cpp:141
TInterface::OperateButtonClick
void __fastcall OperateButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1952
TInterface::WhiteBgndMenuItem
TMenuItem * WhiteBgndMenuItem
Definition: InterfaceUnit.h:402
TTrack::IsReadyForOperation
bool IsReadyForOperation()
Indicates whether or not the railway is ready for saving as a '.rly' file and for operation.
Definition: TrackUnit.h:721
TInterface::ContinuationAutoSignals
void ContinuationAutoSignals(int Caller, TDateTime Now)
Deal with signal resetting on auto signal routes that extend to continuations where trains have depar...
Definition: InterfaceUnit.cpp:13777
TTrainController::CrashWarning
bool CrashWarning
Definition: TrainUnit.h:702
TInterface::LoadInterface
void LoadInterface(int Caller, std::ifstream &SessionFile)
Load the interface part of a session file.
Definition: InterfaceUnit.cpp:15739
TInterface::SpeedButton2
TSpeedButton * SpeedButton2
Definition: InterfaceUnit.h:483
TTrain::PlotTrain
void PlotTrain(int Caller, TDisplay *Disp)
Plots the train on the display in normal (zoomed-in) mode.
Definition: TrainUnit.cpp:7470
TInterface::AutoSigsFlag
bool AutoSigsFlag
true when AutoSig route building selected during operation
Definition: InterfaceUnit.h:897
TInterface::SetRouteButtonsInfoCaptionAndRouteNotStarted
void SetRouteButtonsInfoCaptionAndRouteNotStarted(int Caller)
Enables or disables the route type buttons depending on the route mode, sets the information panel me...
Definition: InterfaceUnit.cpp:17110
TInterface::MoveForwardsMenuItem
TMenuItem * MoveForwardsMenuItem
Definition: InterfaceUnit.h:440
TInterface::YardEdit
TEdit * YardEdit
Definition: InterfaceUnit.h:99
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3248
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:3989
TInterface::Paused
@ Paused
Definition: InterfaceUnit.h:843
TTrainController::SaveSessionTrains
void SaveSessionTrains(int Caller, std::ofstream &SessionFile)
save trains to a session file
Definition: TrainUnit.cpp:13809
TInterface::SpeedButton41
TSpeedButton * SpeedButton41
Definition: InterfaceUnit.h:522
TInterface::TrackInfoMenuItem
TMenuItem * TrackInfoMenuItem
Definition: InterfaceUnit.h:421
TRailGraphics::SpeedBut73NormBlackGlyph
Graphics::TBitmap * SpeedBut73NormBlackGlyph
Definition: GraphicUnit.h:1042
TInterface::Operating
@ Operating
Definition: InterfaceUnit.h:843
TTextHandler
A single object that handles text management.
Definition: TextUnit.h:62
TInterface::EditTimetableMenuItemClick
void __fastcall EditTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3073
TInterface::TakeSignallerControlMenuItemClick
void __fastcall TakeSignallerControlMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9403
TInterface::TimetableMode
@ TimetableMode
Definition: InterfaceUnit.h:821
TInterface::ScreenUpButtonClick
void __fastcall ScreenUpButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8233
TInterface::ShowHideTTButtonClick
void __fastcall ShowHideTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3243
TInterface::ImageMenu
TMenuItem * ImageMenu
Definition: InterfaceUnit.h:427
TInterface::LoadGroundSignalGlyphs
void LoadGroundSignalGlyphs(int Caller)
In trackbuild display ground signal types on signal buttons.
Definition: InterfaceUnit.cpp:17967
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:163
TInterface::OneEntryTimetableMemo
TMemo * OneEntryTimetableMemo
the single service editing and display area on the right hand side of the timetable edit screen
Definition: InterfaceUnit.h:374
TInterface::SelectBitmapVLoc
int SelectBitmapVLoc
the original (prior to moving & after finished moving) VLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1014
TInterface::LengthOKButtonClick
void __fastcall LengthOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1279
TInterface::SpeedButton47
TSpeedButton * SpeedButton47
Definition: InterfaceUnit.h:528
TInterface::OutputLog1MouseDown
void __fastcall OutputLog1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10670
NotStarted
@ NotStarted
Definition: TrainUnit.h:80
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4148
TInterface::AppDeactivate
void __fastcall AppDeactivate(TObject *Sender)
Definition: InterfaceUnit.cpp:730
TInterface::UnrestrictedButtonClick
void __fastcall UnrestrictedButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2045
TInterface::ExportTTMenuItem
TMenuItem * ExportTTMenuItem
Definition: InterfaceUnit.h:392
TRailGraphics::SpeedBut71NormBlackGlyph
Graphics::TBitmap * SpeedBut71NormBlackGlyph
Definition: GraphicUnit.h:1040
TInterface::SelectNewGraphicClick
void __fastcall SelectNewGraphicClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11961
TInterface::SpeedButtonClick
void __fastcall SpeedButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:855
TTrack::GetHLocMax
int GetHLocMax()
Definition: TrackUnit.h:765
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3143
TInterface::ErrorButtonClick
void __fastcall ErrorButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10097
TTrainController::SPADEvents
int SPADEvents
Definition: TrainUnit.h:746
TInterface::PasteTTEntryButton
TButton * PasteTTEntryButton
Definition: InterfaceUnit.h:131
TInterface::SpeedButton139
TSpeedButton * SpeedButton139
Definition: InterfaceUnit.h:620
TInterface::SpeedButton3
TSpeedButton * SpeedButton3
Definition: InterfaceUnit.h:484
TTrain::ZeroPowerNoRepeatShuttleMessage
bool ZeroPowerNoRepeatShuttleMessage
Definition: TrainUnit.h:307
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TInterface::SetLevel2PrefDirMode
void SetLevel2PrefDirMode(int Caller)
Sets the Level2PrefDirMode user mode, using the Level2PrefDirMode variable to determine the mode.
Definition: InterfaceUnit.cpp:13506
TInterface::SetGapsButton
TBitBtn * SetGapsButton
Definition: InterfaceUnit.h:63
TTrain::ActionVectorEntryPtr
TActionVectorEntry * ActionVectorEntryPtr
points to the current position in the ActionVector (a member of the TTrainDataEntry class)
Definition: TrainUnit.h:335
TTrainDataEntry
Contains all data for a single train.
Definition: TrainUnit.h:177
clSignalStopBackground
#define clSignalStopBackground
Definition: GraphicUnit.h:299
TTrainController::LateDeps
int LateDeps
Definition: TrainUnit.h:739
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:16845
TInterface::ExitMenuItemClick
void __fastcall ExitMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5260
TrackUnit.h
TInterface::SpeedButton29
TSpeedButton * SpeedButton29
Definition: InterfaceUnit.h:510
TInterface::SpeedButton35
TSpeedButton * SpeedButton35
Definition: InterfaceUnit.h:516
TInterface::ScreenDownButtonClick
void __fastcall ScreenDownButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8173
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:17036
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:8096
TDisplay::ClearDisplay
void ClearDisplay(int Caller)
Empty the display.
Definition: DisplayUnit.cpp:182
TDisplay::Top
int Top()
Return the top pixel position of the screen.
Definition: DisplayUnit.h:120
TInterface::ExitPrefDirButtonClick
void __fastcall ExitPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1914
TInterface::SaveErrorFile
void SaveErrorFile()
Save the error log after an error has been thrown - no need for a caller.
Definition: InterfaceUnit.cpp:17212
TTrain::SendMissedActionLogs
void SendMissedActionLogs(int Caller, int IncNum, TActionVectorEntry *Ptr)
Missed actions (see NameInTimetableBeforeCDT above) sent to the performance log and performance file.
Definition: TrainUnit.cpp:5812
TInterface::SpeedVariableLabel2
TLabel * SpeedVariableLabel2
Definition: InterfaceUnit.h:112
TInterface::TrainInfoMenuItem
TMenuItem * TrainInfoMenuItem
Definition: InterfaceUnit.h:423
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1393
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1479
TInterface::TrainStatusInfoOnOffMenuItemClick
void __fastcall TrainStatusInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5324
TInterface::ConverttoRightHandSignalsMenuItem
TMenuItem * ConverttoRightHandSignalsMenuItem
Definition: InterfaceUnit.h:445
TInterface::SpeedButton96
TSpeedButton * SpeedButton96
Definition: InterfaceUnit.h:577
TInterface::TTClockxHalfButtonClick
void __fastcall TTClockxHalfButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11436
TInterface::OutputLog3
TLabel * OutputLog3
Definition: InterfaceUnit.h:273
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
TOnePrefDir::ExternalStorePrefDirElement
void ExternalStorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map - used by other classes.
Definition: TrackUnit.h:1308
clB5G5R4
#define clB5G5R4
Definition: GraphicUnit.h:285
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:656
TInterface::SaveImageNoGridMenuItemClick
void __fastcall SaveImageNoGridMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2422
TInterface::SpeedButton25
TSpeedButton * SpeedButton25
Definition: InterfaceUnit.h:506
TInterface::HelpMenu
TMenuItem * HelpMenu
Definition: InterfaceUnit.h:433
TInterface::TrackOKButtonClick
void __fastcall TrackOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:880
TTrainController::CheckSessionLockedRoutes
bool CheckSessionLockedRoutes(int Caller, std::ifstream &SessionFile)
Part of the session file integrity check for locked routes, true for success.
Definition: TrainUnit.cpp:13913
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:2871
TInterface::GapsSetImage
TImage * GapsSetImage
Definition: InterfaceUnit.h:255
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:221
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TInterface::LocationNameComboBoxKeyUp
void __fastcall LocationNameComboBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4537
TInterface::RevertToOriginalRouteSelector
void RevertToOriginalRouteSelector(int Caller)
Clears any route start markers, enables or disables the route cancel button, and resets the informati...
Definition: InterfaceUnit.cpp:12429
TInterface::FileIntegrityCheck
bool FileIntegrityCheck(int Caller, char *FileName) const
Check integrity of a railway file prior to loading, return true for success.
Definition: InterfaceUnit.cpp:12276
TInterface::TTLastServicePtr
TTEVPtr TTLastServicePtr
timetable entry value pointers used during timetable editing
Definition: InterfaceUnit.h:1077
TTrainController::CheckSessionTrains
bool CheckSessionTrains(int Caller, std::ifstream &InFile)
Part of the session file integrity check for train entries, true for success.
Definition: TrainUnit.cpp:13851
TInterface::SpeedButton126
TSpeedButton * SpeedButton126
Definition: InterfaceUnit.h:607
TakeSignallerControl
@ TakeSignallerControl
Definition: TrainUnit.h:49
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:11030
Simple
@ Simple
Definition: TrackUnit.h:63
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:688
TTrain::ZeroPowerNoRepeatShuttleOrNewServiceMessage
bool ZeroPowerNoRepeatShuttleOrNewServiceMessage
flags to indicate whether the respective message has been sent
Definition: TrainUnit.h:308
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:39
TInterface::SetInitialTrackModeEditMenu
void SetInitialTrackModeEditMenu()
Enables or disables the initial Edit mode submenu items in Track mode.
Definition: InterfaceUnit.cpp:17740
TInterface::DeleteMenuItem
TMenuItem * DeleteMenuItem
Definition: InterfaceUnit.h:415
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2495
TInterface::ChangeDirectionMenuItemClick
void __fastcall ChangeDirectionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9594
TInterface::PointsFlashDuration
float PointsFlashDuration
duration of the flash period when changing points manually
Definition: InterfaceUnit.h:973
TInterface::LocationNameComboBoxClick
void __fastcall LocationNameComboBoxClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4466
TInterface::TLevel2OperMode
TLevel2OperMode
Definition: InterfaceUnit.h:842
TInterface::ConsecSignalsRoute
bool ConsecSignalsRoute
true when AutoSig or preferred route building selected during operation (always same state as Preferr...
Definition: InterfaceUnit.h:899
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:11258
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5173
TTrain::BackgroundColour
TColor BackgroundColour
the background colour of the train's headcode graphics
Definition: TrainUnit.h:450
TInterface::LengthCancelButtonClick
void __fastcall LengthCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1461
TTrain
Definition: TrainUnit.h:271
TInterface::OutputLog5
TLabel * OutputLog5
Definition: InterfaceUnit.h:275
TTrainController::CheckTimeValidity
bool CheckTimeValidity(int Caller, AnsiString TimeStr, TDateTime &Time)
returns true if the time complies with requirements
Definition: TrainUnit.cpp:9559
clSignallerStopped
#define clSignallerStopped
Definition: GraphicUnit.h:298
TTextHandler::SelectTextVector
TTextVector SelectTextVector
Definition: TextUnit.h:69
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:150
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:9726
TInterface::CallOnImage
TImage * CallOnImage
Definition: InterfaceUnit.h:241
TInterface::PerformancePanelDragStartY
int PerformancePanelDragStartY
as above for 'Y'
Definition: InterfaceUnit.h:1005
TInterface::LocationNameTextBox
TEdit * LocationNameTextBox
edit box that accepts location names
Definition: InterfaceUnit.h:93
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:541
TInterface::SaveSessionFlag
bool SaveSessionFlag
true when a session save command has been given - implemented at next clock tick
Definition: InterfaceUnit.h:927
TTrainController::ContinuationTrainExpectationMultiMap
TContinuationTrainExpectationMultiMap ContinuationTrainExpectationMultiMap
Multimap for TContinuationTrainExpectationEntry objects, the access key is the expectation time.
Definition: TrainUnit.h:769
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:6478
TInterface::SpeedButton73
TSpeedButton * SpeedButton73
Definition: InterfaceUnit.h:554
TInterface::TTLabel4
TLabel * TTLabel4
Definition: InterfaceUnit.h:321
TTrain::StoppedForTrainInFront
bool StoppedForTrainInFront
Definition: TrainUnit.h:427
GapJump
@ GapJump
Definition: TrackUnit.h:63
TInterface::Level2OperMode
enum TInterface::TLevel2OperMode Level2OperMode
TInterface::SigsOnRightImage1
TImage * SigsOnRightImage1
Definition: InterfaceUnit.h:261
TInterface::SaveRailwayPDPButton
TBitBtn * SaveRailwayPDPButton
Save button on PrefDirPanel.
Definition: InterfaceUnit.h:118
TInterface::SpeedButton62
TSpeedButton * SpeedButton62
Definition: InterfaceUnit.h:543
TInterface::SpeedButton58
TSpeedButton * SpeedButton58
Definition: InterfaceUnit.h:539
TTrainController::MissedStops
int MissedStops
Definition: TrainUnit.h:741
TInterface::TempTTFileName
AnsiString TempTTFileName
the name for the temporary file used to save loaded timetables for storage in session files & error l...
Definition: InterfaceUnit.h:888
TInterface::PrefDirMode
@ PrefDirMode
Definition: InterfaceUnit.h:821
TInterface::PassRedSignalMenuItem
TMenuItem * PassRedSignalMenuItem
Definition: InterfaceUnit.h:441
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:146
TRailGraphics::bmGreenRect
Graphics::TBitmap * bmGreenRect
Definition: GraphicUnit.h:520
TInterface::TTClockExitButtonClick
void __fastcall TTClockExitButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11302
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:146
TTrack::Raising
@ Raising
Definition: TrackUnit.h:522
TTrainController::FinishedOperation
void FinishedOperation(int Caller)
called when exiting operation mode to delete all trains and timetable data etc
Definition: TrainUnit.cpp:8082
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:551
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:8823
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:78
TTrain::MidElement
int MidElement
Definition: TrainUnit.h:327
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:15392
TInterface::SpeedButton5
TSpeedButton * SpeedButton5
Definition: InterfaceUnit.h:486
TInterface::LocationNameKeyUp
void __fastcall LocationNameKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:1072
TInterface::LoadUserGraphicDialog
TOpenDialog * LoadUserGraphicDialog
Definition: InterfaceUnit.h:468
TAllRoutes::CallonVector
std::vector< TCallonEntry > CallonVector
the store of all call-on entries
Definition: TrackUnit.h:1538
TInterface::OutputLog8MouseDown
void __fastcall OutputLog8MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10738
TInterface::SetPausedOrZoomedInfoCaption
void SetPausedOrZoomedInfoCaption(int Caller)
Sets the information panel message for zoom-out or paused modes.
Definition: InterfaceUnit.cpp:17181
TTrain::LeadElement
int LeadElement
Definition: TrainUnit.h:327
TInterface::CurDir
AnsiString CurDir
the full path to the folder where railway.exe resides
Definition: InterfaceUnit.h:874
TInterface::OneEntryTimetableMemoKeyUp
void __fastcall OneEntryTimetableMemoKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4494
TInterface::RouteCancelButton
TBitBtn * RouteCancelButton
Definition: InterfaceUnit.h:197
TInterface::SpeedButton26
TSpeedButton * SpeedButton26
Definition: InterfaceUnit.h:507
TInterface::HomeButton
TBitBtn * HomeButton
Definition: InterfaceUnit.h:232
TRailGraphics
Handles graphic data & functions, single object defined.
Definition: GraphicUnit.h:308
TInterface::OperatorActionPanelDragStartY
int OperatorActionPanelDragStartY
as above for 'Y'
Definition: InterfaceUnit.h:998
TTrain::RepeatNumber
int RepeatNumber
indicates which of the repeating services this train represents (0 = first service)
Definition: TrainUnit.h:321
TTrainDataEntry::ActionVector
TActionVector ActionVector
all the actions for the train
Definition: TrainUnit.h:195
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:631
TInterface::NewHomeButton
TBitBtn * NewHomeButton
Definition: InterfaceUnit.h:233
TInterface::ResetAll
void ResetAll(int Caller)
Called during ClearEverything and on startup to reset all major railway data values.
Definition: InterfaceUnit.cpp:15125
TInterface::SpeedButton75
TSpeedButton * SpeedButton75
Definition: InterfaceUnit.h:556
TTrainController::LoadSessionLockedRoutes
void LoadSessionLockedRoutes(int Caller, std::ifstream &SessionFile)
load locked routes from a session file
Definition: TrainUnit.cpp:13892
TInterface::DistancesMarked
bool DistancesMarked
true when setting lengths, used to ensure the screen distance markers are redisplayed when the screen...
Definition: InterfaceUnit.h:905
TTrainController::EarlyPasses
int EarlyPasses
Definition: TrainUnit.h:736
TTrain::HeadCode
AnsiString HeadCode
needs own HeadCode because repeat entries will differ from TrainDataEntry.HeadCode
Definition: TrainUnit.h:290
TInterface::TrackBuildPanel
TPanel * TrackBuildPanel
'Build/modify railway' panel
Definition: InterfaceUnit.h:336
TTrain::EntryTime
TDateTime EntryTime
Definition: TrainUnit.h:409
TInterface::CutMoving
@ CutMoving
Definition: InterfaceUnit.h:852
TInterface::SpeedButton134
TSpeedButton * SpeedButton134
Definition: InterfaceUnit.h:615
TInterface::SelectLengthsMenuItem
TMenuItem * SelectLengthsMenuItem
Definition: InterfaceUnit.h:416
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1259
TInterface::SpeedButton72
TSpeedButton * SpeedButton72
Definition: InterfaceUnit.h:553
TInterface::ValidateTimetableButton
TButton * ValidateTimetableButton
Definition: InterfaceUnit.h:143
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:5404
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1399
InterfaceUnit.h
TInterface::CopyMenuItemClick
void __fastcall CopyMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8607
TInterface::PerformanceLogButton
TBitBtn * PerformanceLogButton
Definition: InterfaceUnit.h:199
TInterface::FORMATTEDTT_DIR_NAME
static const UnicodeString FORMATTEDTT_DIR_NAME
Definition: InterfaceUnit.h:837
TInterface::HighLightOneGap
bool HighLightOneGap(int Caller, int &HLoc, int &VLoc)
Called during gap setting to mark a gap with a red ellipse and ask user to select the corresponding g...
Definition: InterfaceUnit.cpp:12198
TTrain::OneLengthAccelDecel
bool OneLengthAccelDecel
set when a train can only move forwards one element before stopping but needs to accelerate for the f...
Definition: TrainUnit.h:357
TTrain::FloatingLabelNextString
AnsiString FloatingLabelNextString(int Caller, TActionVectorEntry *Ptr)
Used in the floating window to display the 'Next' action.
Definition: TrainUnit.cpp:6337
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers
Definition: TrackUnit.h:533
TTrain::FailedTrainNoFinishJoinMessage
bool FailedTrainNoFinishJoinMessage
Definition: TrainUnit.h:302
TInterface::SpeedButton55
TSpeedButton * SpeedButton55
Definition: InterfaceUnit.h:536
TInterface::OperatorActionPanel
TPanel * OperatorActionPanel
new v2.2.0 panel housing the OAListBox with list of trains and times to act
Definition: InterfaceUnit.h:364
TInterface::NextTTEntryButton
TButton * NextTTEntryButton
Definition: InterfaceUnit.h:128
TTextHandler::SelectTextVectorSize
unsigned int SelectTextVectorSize(int Caller)
return the number of items in SelectTextVector
Definition: TextUnit.cpp:510
TInterface::TrackTrainFloat
void TrackTrainFloat(int Caller)
Controls the floating window function, called during the ClockTimer2 function.
Definition: InterfaceUnit.cpp:13834
TDisplay::GetImage
TImage * GetImage()
Return a pointer to the screen image.
Definition: DisplayUnit.h:138
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TInterface::AddLocationNameText
void AddLocationNameText(int Caller, AnsiString Name, int HPos, int VPos, bool UseEnteredPosition)
Add 'Name' to TextVector and display on screen at a position determined by the shape and size of the ...
Definition: InterfaceUnit.cpp:17846
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackElement.at(At)
Definition: TrackUnit.cpp:8929
TTextHandler::CheckTextElementsInFile
bool CheckTextElementsInFile(int Caller, std::ifstream &VecFile)
check the validity of text items in VecFile prior to loading, return true for success
Definition: TextUnit.cpp:343
TInterface::ConverttoRightHandSignalsMenuItemClick
void __fastcall ConverttoRightHandSignalsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11746
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:294
TTrack::GetVLocMax
int GetVLocMax()
Definition: TrackUnit.h:775
TTrainController::LoadSessionContinuationAutoSigEntries
void LoadSessionContinuationAutoSigEntries(int Caller, std::ifstream &SessionFile)
load ContinuationAutoSigEntries from a session file
Definition: TrainUnit.cpp:13975
TInterface::HighlightOneEntryInAllEntriesTTListBox
void HighlightOneEntryInAllEntriesTTListBox(int Caller, int Position)
Called during timetable editing to highlight in red a single entry in the list of all entries in the ...
Definition: InterfaceUnit.cpp:5194
TInterface::DistanceStart
@ DistanceStart
Definition: InterfaceUnit.h:851
TInterface::ErrorMessage
TMemo * ErrorMessage
the text of the error message screen
Definition: InterfaceUnit.h:372
TInterface::ExitPrefDirButton
TBitBtn * ExitPrefDirButton
Definition: InterfaceUnit.h:120
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:696
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:122
TInterface::TrackLengthPanel
TPanel * TrackLengthPanel
the panel that contains the distance/speed setting buttons and edit boxes
Definition: InterfaceUnit.h:357
TUtilities::Format96HHMMSS
AnsiString Format96HHMMSS(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm:ss where hh runs from 00 to 95 & resets when...
Definition: Utilities.cpp:519
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3407
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:981
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:982
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:752
TTrainController::OtherMissedEvents
int OtherMissedEvents
Definition: TrainUnit.h:745
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:419
TInterface::MoveTextOrGraphicButton
TBitBtn * MoveTextOrGraphicButton
Definition: InterfaceUnit.h:66
TTrainDataEntry::Description
AnsiString Description
headcode is the first train's headcode, rest are calculated from repeat information; ServiceReference...
Definition: TrainUnit.h:179
TInterface::RouteContinuing
@ RouteContinuing
Definition: InterfaceUnit.h:856
TTrain::ExitSpeedHalf
double ExitSpeedHalf
speed when half way into the next element
Definition: TrainUnit.h:377
SignalPost
@ SignalPost
Definition: TrackUnit.h:63
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:8061
TTrain::LastActionTime
TDateTime LastActionTime
time of the last timetabled action, used to ensure at least a 30 second delay before the next action
Definition: TrainUnit.h:413
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:15546
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:420
TInterface::InfoPanel
TPanel * InfoPanel
the general information panel (with blue 'i' symbol)
Definition: InterfaceUnit.h:351
TInterface::TextOrUserGraphicGridButtonClick
void __fastcall TextOrUserGraphicGridButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1679
TInterface::FormKeyDown
void __fastcall FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:10196
TInterface::MoveTTEntryDownButton
TButton * MoveTTEntryDownButton
Definition: InterfaceUnit.h:134
TInterface::CheckTimetableFromSessionFile
bool CheckTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
Check the timetable file embedded within a session file & return false for error, called during Sessi...
Definition: InterfaceUnit.cpp:16293
TRailGraphics::SpeedBut71GrndBlackGlyph
Graphics::TBitmap * SpeedBut71GrndBlackGlyph
Definition: GraphicUnit.h:1048
TInterface::DeleteTTEntryButtonClick
void __fastcall DeleteTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3696
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:6492
TInterface::WarningFlashCount
int WarningFlashCount
increments each clock cycle to a max. of 4 then resets to 0, used to toggle bool WarningFlash - see a...
Definition: InterfaceUnit.h:1040
TInterface::StartWholeRailwayMoveHPos
int StartWholeRailwayMoveHPos
mouse X position when start to move the whole railway
Definition: InterfaceUnit.h:1018
TInterface::SpeedButton93
TSpeedButton * SpeedButton93
Definition: InterfaceUnit.h:574
TInterface::SpeedButton119
TSpeedButton * SpeedButton119
Definition: InterfaceUnit.h:600
TInterface::SelectedGraphicFileName
AnsiString SelectedGraphicFileName
filename for selected graphic set during LoadGraphic
Definition: InterfaceUnit.h:892
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:7439
TInterface::TrackBuildPanelLabel
TLabel * TrackBuildPanelLabel
label to the left of TrackBuildPanel
Definition: InterfaceUnit.h:294
clNormalBackground
#define clNormalBackground
Definition: GraphicUnit.h:297
TInterface::TTClockAdjButtonClick
void __fastcall TTClockAdjButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11271
TInterface::RAILWAY_DIR_NAME
static const UnicodeString RAILWAY_DIR_NAME
Definition: InterfaceUnit.h:832
TTrainController::SecondPassActions
bool SecondPassActions(int Caller, bool GiveMessages)
Carry out further detailed timetable consistency checks, return true for success.
Definition: TrainUnit.cpp:10597
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:15531
TInterface::SPADImage
TImage * SPADImage
Definition: InterfaceUnit.h:245
TInterface::AddTrackButton
TBitBtn * AddTrackButton
Definition: InterfaceUnit.h:62
TInterface::MainMenu1
TMainMenu * MainMenu1
the program menu
Definition: InterfaceUnit.h:369
TInterface::OutputLog7MouseDown
void __fastcall OutputLog7MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10728
Concourse
@ Concourse
Definition: TrackUnit.h:65
TTextHandler::TTextVectorIterator
std::vector< TTextItem >::iterator TTextVectorIterator
Definition: TextUnit.h:66
TTrainController::SPADRisks
int SPADRisks
Definition: TrainUnit.h:747
TInterface::LocationNamesNotSetImage
TImage * LocationNamesNotSetImage
Definition: InterfaceUnit.h:258
TInterface::FloatingPanel
TPanel * FloatingPanel
new for v2.2.0 where label sits in it and it autosizes to the label. Labels are not TWinControls so t...
Definition: InterfaceUnit.h:361
TRailGraphics::SpeedBut68NormBlackGlyph
Graphics::TBitmap * SpeedBut68NormBlackGlyph
Definition: GraphicUnit.h:1037
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:705
TInterface::SaveMenuItemClick
void __fastcall SaveMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2354
TInterface::ScreenGridButtonClick
void __fastcall ScreenGridButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1784
TTrain::EntrySpeed
double EntrySpeed
speed at which the train enters the next element
Definition: TrainUnit.h:375
TInterface::UserGraphicMoveHPos
int UserGraphicMoveHPos
Definition: InterfaceUnit.h:1038
TInterface::PassRedSignalMenuItemClick
void __fastcall PassRedSignalMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9866
TInterface::ReselectMenuItem
TMenuItem * ReselectMenuItem
Definition: InterfaceUnit.h:408
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:11714
TInterface::ClearEverything
bool ClearEverything(int Caller)
First check whether a railway file has changed and if so ask user if really wants to close it without...
Definition: InterfaceUnit.cpp:12226
TInterface::PrefDirContinuing
@ PrefDirContinuing
Definition: InterfaceUnit.h:847
TTrain::TrainGone
bool TrainGone
set when train has left the railway, so it can be removed from the display at the next clock tick
Definition: TrainUnit.h:423
TRailGraphics::SpeedBut70NormBlackGlyph
Graphics::TBitmap * SpeedBut70NormBlackGlyph
Definition: GraphicUnit.h:1039
TTrainController::OnTimePasses
int OnTimePasses
Definition: TrainUnit.h:744
TInterface::SaveAsMenuItem
TMenuItem * SaveAsMenuItem
Definition: InterfaceUnit.h:388
TInterface::MoveTextOrGraphicButtonClick
void __fastcall MoveTextOrGraphicButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:994
TTrainController::SigSHigh
bool SigSHigh
Definition: TrainUnit.h:713
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4073
TInterface::ZoomButton
TBitBtn * ZoomButton
Definition: InterfaceUnit.h:234
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1596
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:94
TInterface::CopyTTEntryButton
TButton * CopyTTEntryButton
Definition: InterfaceUnit.h:129
TInterface::SpeedButton76
TSpeedButton * SpeedButton76
Definition: InterfaceUnit.h:557
TTrain::StoppedAfterSPAD
bool StoppedAfterSPAD
Definition: TrainUnit.h:427
TInterface::SpeedButton145
TSpeedButton * SpeedButton145
Definition: InterfaceUnit.h:626
TInterface::NoPrefDirMode
@ NoPrefDirMode
Definition: InterfaceUnit.h:847
TInterface::SpeedButton88
TSpeedButton * SpeedButton88
Definition: InterfaceUnit.h:569
TTrainController::OnTimeArrivals
int OnTimeArrivals
Definition: TrainUnit.h:742
TInterface::MoveTTEntryDownButtonClick
void __fastcall MoveTTEntryDownButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4182
TInterface::PerformanceLogBox
TMemo * PerformanceLogBox
the performance log displayed during operation
Definition: InterfaceUnit.h:376
TRailGraphics::SpeedBut72GrndBlackGlyph
Graphics::TBitmap * SpeedBut72GrndBlackGlyph
Definition: GraphicUnit.h:1049
TInterface::SpeedButton28
TSpeedButton * SpeedButton28
Definition: InterfaceUnit.h:509
TAllRoutes::LevelCrossingBarrierUpDelay
const float LevelCrossingBarrierUpDelay
the full value in seconds for which the level crossing flashes prior to closing to trains
Definition: TrackUnit.h:1558
TInterface::SpeedTopLabel
TLabel * SpeedTopLabel
Definition: InterfaceUnit.h:179
TInterface::OperateButton
TBitBtn * OperateButton
Definition: InterfaceUnit.h:193
clFrontCodeSignaller
#define clFrontCodeSignaller
Definition: GraphicUnit.h:295
TInterface::SignallerJoinedByMenuItemClick
void __fastcall SignallerJoinedByMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9687
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:670
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:46
TActionVectorEntry::ArrivalTime
TDateTime ArrivalTime
Definition: TrainUnit.h:106
TTrain::StoppedAtBuffers
bool StoppedAtBuffers
Definition: TrainUnit.h:427
TInterface::SkipFormResizeEvent
bool SkipFormResizeEvent
added at v2.1.0 to avoid calling the event during startup and shutdown
Definition: InterfaceUnit.h:943
TTrackElement::TempMarker
bool TempMarker
Utility marker for program use.
Definition: TrackUnit.h:134
TTrain::Mass
int Mass
in kg
Definition: TrainUnit.h:405
TInterface::TrackInfoOnOffMenuItem
TMenuItem * TrackInfoOnOffMenuItem
Definition: InterfaceUnit.h:422
TDisplay::ShowWarningLog
void ShowWarningLog(int Caller)
Show the warnings after timetable clock adjusted.
Definition: DisplayUnit.cpp:494
TInterface::SpeedButton121
TSpeedButton * SpeedButton121
Definition: InterfaceUnit.h:602
TTrainController::ProcessOneTimetableLine
bool ProcessOneTimetableLine(int Caller, int Count, AnsiString OneLine, bool &EndOfFile, bool FinalCall, bool GiveMessages, bool CheckLocationsExistInRailway)
Carry out preliminary (mainly syntax) validity checks on a single timetable service entry and (if Fin...
Definition: TrainUnit.cpp:8909
TInterface::SaveAsMenuItemClick
void __fastcall SaveAsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2405
TTextItem
A single piece of text that can be displayed on the railway.
Definition: TextUnit.h:36
TInterface::SpeedButton136
TSpeedButton * SpeedButton136
Definition: InterfaceUnit.h:617
TInterface::PointFlash
TGraphicElement * PointFlash
Definition: InterfaceUnit.h:1054
TInterface::TrackLinkedImage
TImage * TrackLinkedImage
Definition: InterfaceUnit.h:253
TTrain::LeadExitPos
int LeadExitPos
Definition: TrainUnit.h:327
TInterface::SelectPickedUp
bool SelectPickedUp
true when a valid selected screen area has been clicked after a 'Copy' or 'Cut' selected in the 'Edit...
Definition: InterfaceUnit.h:935
TDisplay::ResetZoomOutOffsets
void ResetZoomOutOffsets()
Reset the zoomed-out screen display to the 'Home' position.
Definition: DisplayUnit.h:208
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:155
TInterface::DevelopmentPanel
TPanel * DevelopmentPanel
used for diagnostic purposes, made visible by ctrl+ alt+ 3
Definition: InterfaceUnit.h:359
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1615
TInterface::PerformancePanel
TPanel * PerformancePanel
displays the operating performance log
Definition: InterfaceUnit.h:353
TTrainController::DerailWarning
bool DerailWarning
Definition: TrainUnit.h:702
TInterface::CopyMoving
@ CopyMoving
Definition: InterfaceUnit.h:852
TInterface::TimetableEditPanel
TPanel * TimetableEditPanel
the large panel that contains all the main timetable components
Definition: InterfaceUnit.h:345
TInterface::RouteMode
enum TInterface::@0 RouteMode
route building modes
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:90
TInterface::TrainStatusInfoOnOffMenuItem
TMenuItem * TrainStatusInfoOnOffMenuItem
Definition: InterfaceUnit.h:424
TInterface::SetLengthsButtonClick
void __fastcall SetLengthsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1258
TInterface::SaveTTEntryButton
TButton * SaveTTEntryButton
Definition: InterfaceUnit.h:135
TInterface::SpeedButton37
TSpeedButton * SpeedButton37
Definition: InterfaceUnit.h:518
TInterface::BaseMode
@ BaseMode
Definition: InterfaceUnit.h:821
TInterface::SpeedEditBoxKeyUp
void __fastcall SpeedEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:10966
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
Definition: TrackUnit.cpp:9608
TInterface::MirrorMenuItem
TMenuItem * MirrorMenuItem
Definition: InterfaceUnit.h:412
TInterface::EveryPrefDir
TOnePrefDir * EveryPrefDir
all the Pref Dir elements in the railway
Definition: InterfaceUnit.h:1065
TTrainController::TotLateDepMins
float TotLateDepMins
Definition: TrainUnit.h:729
TDisplay::ZoomOutFlag
bool ZoomOutFlag
true when zoomed-out
Definition: DisplayUnit.h:69
TInterface::OutputLog8
TLabel * OutputLog8
Definition: InterfaceUnit.h:278
TInterface::SpeedButton1
TSpeedButton * SpeedButton1
See Speedbutton1 detail for track element allocations.
Definition: InterfaceUnit.h:482
TTrainController::TrainVector
TTrainVector TrainVector
vector containing all trains currently in the railway
Definition: TrainUnit.h:777
TInterface::SaveAsSubroutine
void SaveAsSubroutine(int Caller)
Used to save a railway when not already saved - e.g. when not already named or when the 'Save as' men...
Definition: InterfaceUnit.cpp:17643
TInterface::MainScreenMouseDown2
void MainScreenMouseDown2(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
Called when mouse button clicked in zoom-in mode.
Definition: InterfaceUnit.cpp:5501
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1405
TInterface::RepairFailedTrainMenuItemClick
void __fastcall RepairFailedTrainMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9776
TInterface::AddLocationName
@ AddLocationName
Definition: InterfaceUnit.h:851
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:7387
TTrack::IsTrackFinished
bool IsTrackFinished()
Indicates whether or not the track has been successfully linked together.
Definition: TrackUnit.h:727
TAllRoutes::AllRoutesClear
void AllRoutesClear()
Erases all routes from AllRoutesVector and from Route2MultiMap.
Definition: TrackUnit.h:1586
TRailGraphics::SpeedBut74GrndBlackGlyph
Graphics::TBitmap * SpeedBut74GrndBlackGlyph
Definition: GraphicUnit.h:1051
TAllRoutes::PointsDelay
const float PointsDelay
the value in seconds for which points flash prior to being changed. Used for the points flash period ...
Definition: TrackUnit.h:1562
TInterface::SaveSession
void SaveSession(int Caller)
Save a session file - see LoadSession for details of additions to the session file.
Definition: InterfaceUnit.cpp:15331
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:49
TAllRoutes::SignalsDelay
const float SignalsDelay
the value in seconds for which signals flash prior to being changed. Used for the route flash period ...
Definition: TrackUnit.h:1564
TDisplay::GetFont
TFont * GetFont()
Return the current screen font.
Definition: DisplayUnit.h:132
TInterface::SpeedButton10
TSpeedButton * SpeedButton10
Definition: InterfaceUnit.h:491
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:284
TInterface::SpeedButton103
TSpeedButton * SpeedButton103
Definition: InterfaceUnit.h:584
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:752
TTrainController::TotEarlyArrMins
float TotEarlyArrMins
values for performance file summary
Definition: TrainUnit.h:725
TInterface::PerformancePanelStartDrag
void __fastcall PerformancePanelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:5429
TInterface::TempCursorSet
bool TempCursorSet
indicates that a screen cursor has been stored in TempCursor for redisplay after a temporary cursor (...
Definition: InterfaceUnit.h:945
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:10517
TInterface::SpeedButton85
TSpeedButton * SpeedButton85
Definition: InterfaceUnit.h:566
TInterface::PasteMenuItemClick
void __fastcall PasteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9193
TInterface::MainScreenMouseUp
void __fastcall MainScreenMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:7182
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:86
TInterface::SaveTempTimetableFile
void SaveTempTimetableFile(int Caller, AnsiString InFileName)
Save a timetable as a temporary file either on loading directly or on loading a session file....
Definition: InterfaceUnit.cpp:17404
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1568
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:107
TInterface::RotateMenuItemClick
void __fastcall RotateMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8742
TTrainDataEntry::SignallerSpeed
int SignallerSpeed
in km/h for use when under signaller control
Definition: TrainUnit.h:191
TInterface::OverallDistance
int OverallDistance
Definition: InterfaceUnit.h:1000
TInterface::SpeedButton105
TSpeedButton * SpeedButton105
Definition: InterfaceUnit.h:586
TInterface::SpeedButton83
TSpeedButton * SpeedButton83
Definition: InterfaceUnit.h:564
TTrain::AbleToMove
bool AbleToMove(int Caller)
Indicates that a train is not prevented from moving - used to allow appropriate popup menu options wh...
Definition: TrainUnit.cpp:6237
TTrainController::MTBFHours
double MTBFHours
Mean time between failures in timetable clock hours.
Definition: TrainUnit.h:716
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:10997
TInterface::RestoreAllDefaultLengthsButtonClick
void __fastcall RestoreAllDefaultLengthsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1589
TInterface::SpeedButton131
TSpeedButton * SpeedButton131
Definition: InterfaceUnit.h:612
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:12536
TInterface::FlipMenuItemClick
void __fastcall FlipMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8626
TInterface::TrainTTInfoOnOffMenuItem
TMenuItem * TrainTTInfoOnOffMenuItem
Definition: InterfaceUnit.h:425
TInterface::AllSetUpFlag
bool AllSetUpFlag
false during initial start up, true when all set up to allow MasterClock to start
Definition: InterfaceUnit.h:895
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3225
TInterface::LocationNameButton
TBitBtn * LocationNameButton
Definition: InterfaceUnit.h:67
TInterface::SpeedButton101
TSpeedButton * SpeedButton101
Definition: InterfaceUnit.h:582
TTrain::TrainMode
TTrainMode TrainMode
mode of operation - either Timetable (running under timetable control) or Signaller (running under si...
Definition: TrainUnit.h:415
TInterface::LoadRailway
void LoadRailway(int Caller, AnsiString LoadFileName)
Load a railway file. The Active elements marker now has a '1' at the end if there are user graphics t...
Definition: InterfaceUnit.cpp:2225
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:9655
TInterface::TextOrUserGraphicGridButton
TBitBtn * TextOrUserGraphicGridButton
Definition: InterfaceUnit.h:69
TInterface::PointFlashVectorPosition
int PointFlashVectorPosition
Definition: InterfaceUnit.h:1007
TInterface::AddSubMinsBoxKeyUp
void __fastcall AddSubMinsBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4519
TInterface::ExitOperationButtonClick
void __fastcall ExitOperationButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2134
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1498
TInterface::TTClockAdd1hButtonClick
void __fastcall TTClockAdd1hButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11511
TUtilities::Format96HHMM
AnsiString Format96HHMM(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm where hh runs from 00 to 95 & resets when it...
Definition: Utilities.cpp:534
TInterface::TTClockx2ButtonClick
void __fastcall TTClockx2ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11341
TInterface::PerformancePanelDragStartX
int PerformancePanelDragStartX
mouse 'X' position when the performance panel begins to be dragged
Definition: InterfaceUnit.h:1003
TInterface::SpeedButton45
TSpeedButton * SpeedButton45
Definition: InterfaceUnit.h:526
TInterface::SpeedEditBox2KeyUp
void __fastcall SpeedEditBox2KeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11120
TInterface::SavedFileName
AnsiString SavedFileName
the full path and filename of the loaded railway
Definition: InterfaceUnit.h:886
TInterface::PlanPrefDirsMenuItemClick
void __fastcall PlanPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1811
TInterface::OperatingPanel
TPanel * OperatingPanel
'Operate railway' panel
Definition: InterfaceUnit.h:342
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:813
TInterface::SpeedButton141
TSpeedButton * SpeedButton141
Definition: InterfaceUnit.h:622
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, bool ConsecSignals, TDisplay *Disp)
Plot & open (to trains) all level crossings linked to TrackElement.
Definition: TrackUnit.cpp:5611
TInterface::ShowOperatorActionPanel
bool ShowOperatorActionPanel
true when the 'trains needing action' button has been clicked during operation (new at v2....
Definition: InterfaceUnit.h:957
TTrack::GetGapVLoc
int GetGapVLoc()
Definition: TrackUnit.h:760
TInterface::SpeedButton124
TSpeedButton * SpeedButton124
Definition: InterfaceUnit.h:605
TUtilities::CheckFileString
bool CheckFileString(std::ifstream &InFile)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success
Definition: Utilities.cpp:355
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:10817
TRailGraphics::bmGrid
Graphics::TBitmap * bmGrid
Definition: GraphicUnit.h:521
TInterface::RestoreFocusPanel
TPanel * RestoreFocusPanel
Panel used to restore focus to Interface to enable cursor keys to move screen.
Definition: InterfaceUnit.h:333
TInterface::BlackBgndMenuItem
TMenuItem * BlackBgndMenuItem
Definition: InterfaceUnit.h:403
SignallerControlStop
@ SignallerControlStop
Definition: TrainUnit.h:51
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:705
TInterface::FloatingLabel
TLabel * FloatingLabel
the floating window that displays track & train information
Definition: InterfaceUnit.h:314
TInterface::NewTTEntryButton
TButton * NewTTEntryButton
Definition: InterfaceUnit.h:137
TTrainController::ExcessLCDownMins
float ExcessLCDownMins
total excess time in minutes over the 3 minutes barriers down allowance for level crossings
Definition: TrainUnit.h:723
TInterface::SubMinsButtonClick
void __fastcall SubMinsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3448
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:345
TInterface::TimetableControlMenuItemClick
void __fastcall TimetableControlMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9476
TTrack::TActiveTrackElementNameIterator
TActiveTrackElementNameMap::iterator TActiveTrackElementNameIterator
Definition: TrackUnit.h:615
TInterface::DistanceBox
TEdit * DistanceBox
distance/speed setting edit box that accepts distances
Definition: InterfaceUnit.h:89
TInterface::SpeedButton142
TSpeedButton * SpeedButton142
Definition: InterfaceUnit.h:623
TInterface::PresetAutoSigRoutesButton
TBitBtn * PresetAutoSigRoutesButton
Definition: InterfaceUnit.h:198
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:132
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:116
TInterface::TTLabel12
TLabel * TTLabel12
Definition: InterfaceUnit.h:328
TInterface::TTServiceSyntaxCheckButtonClick
void __fastcall TTServiceSyntaxCheckButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4033
TInterface::SpeedButton57
TSpeedButton * SpeedButton57
Definition: InterfaceUnit.h:538
TInterface::TTClockSpeed
float TTClockSpeed
rate at which the timetable clock runs 1 = normal
Definition: InterfaceUnit.h:977
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:53
TDisplay::PlotAbsolute
void PlotAbsolute(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Definition: DisplayUnit.cpp:420
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5132
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1532
TInterface::TTClockx4ButtonClick
void __fastcall TTClockx4ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11360
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:11651
TInterface::SaveImageAndPrefDirsMenuItemClick
void __fastcall SaveImageAndPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2611
TInterface::AddMinsButton
TButton * AddMinsButton
Definition: InterfaceUnit.h:140
SignallerStepForward
@ SignallerStepForward
Definition: TrainUnit.h:51
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:770
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:521
TInterface::SpeedButton60
TSpeedButton * SpeedButton60
Definition: InterfaceUnit.h:541
TInterface::TrackInfoOnOffMenuItemClick
void __fastcall TrackInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5301
TTrack::WriteTrackToImage
void WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3433
TTrainController::OpTimeToActUpdateCounter
unsigned int OpTimeToActUpdateCounter
new v2.2.0, incremented in Interface.cpp, controls updating for OpTimeToActPanel
Definition: TrainUnit.h:761
TTrain::BeingCalledOn
bool BeingCalledOn
in course of being called on to a station
Definition: TrainUnit.h:341
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:216
TInterface::AZOrderButtonClick
void __fastcall AZOrderButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4838
TInterface::HiddenScreen
TImage * HiddenScreen
a hidden copy of the railway display screen used during ClearandRebuildRailway (see below) to avoid f...
Definition: InterfaceUnit.h:1060
TInterface::PerformancePanelLabelStartDrag
void __fastcall PerformancePanelLabelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:10107
TInterface::LoadPerformanceFile
void LoadPerformanceFile(int Caller, std::ifstream &InFile)
Load the performance file part of a sessionfile.
Definition: InterfaceUnit.cpp:17035
TInterface::OutputLog4MouseDown
void __fastcall OutputLog4MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10699
TInterface::AddGraphic
@ AddGraphic
Definition: InterfaceUnit.h:851
TInterface::SetLevel1Mode
void SetLevel1Mode(int Caller)
Sets the Level1 user mode, using the Level1Mode variable to determine the mode.
Definition: InterfaceUnit.cpp:12458
TInterface::NewHomeButtonClick
void __fastcall NewHomeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8461
TInterface::OutputLog4
TLabel * OutputLog4
Definition: InterfaceUnit.h:274
TInterface::FontDialog
TFontDialog * FontDialog
font change dialog
Definition: InterfaceUnit.h:473
TInterface::TrackSelecting
@ TrackSelecting
Definition: InterfaceUnit.h:852
TTrainController::TotLateArrMins
float TotLateArrMins
Definition: TrainUnit.h:728
TInterface::Level2PrefDirMode
enum TInterface::TLevel2PrefDirMode Level2PrefDirMode
TInterface::OperatingPanelLabel
TLabel * OperatingPanelLabel
displays 'Operation' or 'Disabled' on the operating panel during operation for running or paused
Definition: InterfaceUnit.h:302
TInterface::DivergingPointVectorPosition
int DivergingPointVectorPosition
Definition: InterfaceUnit.h:1007
TInterface::OAListBoxMouseUp
void __fastcall OAListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:4611
TTrainController::PlotAllTrainsInZoomOutMode
void PlotAllTrainsInZoomOutMode(int Caller, bool Flash)
Plots all trains on screen in zoomed-out mode, state of 'Flash' determines whether the flashing train...
Definition: TrainUnit.cpp:14128
TInterface::SpeedButton108
TSpeedButton * SpeedButton108
Definition: InterfaceUnit.h:589
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1355
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:7354
TInterface::SavePerformanceFile
void SavePerformanceFile(int Caller, std::ofstream &OutFile)
Save performance file part of a session file.
Definition: InterfaceUnit.cpp:17090
TTextItem::Font
TFont * Font
the text font
Definition: TextUnit.h:52
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1509
TTrain::SignallerStopped
bool SignallerStopped
Definition: TrainUnit.h:427
TDisplay::SetFont
void SetFont(TFont *Font)
Set the screen font to 'Font'.
Definition: DisplayUnit.h:215
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1499
TTrain::TrainDataEntryPtr
TTrainDataEntry * TrainDataEntryPtr
points to the current position in the timetable's TrainDataVector
Definition: TrainUnit.h:333
TInterface::TTLabel13
TLabel * TTLabel13
Definition: InterfaceUnit.h:329
TTrainDataEntry::StartSpeed
int StartSpeed
in km/h
Definition: TrainUnit.h:193
TTrainDataEntry::NumberOfTrains
int NumberOfTrains
number of repeats + 1
Definition: TrainUnit.h:189
TTrainController::Derailments
int Derailments
Definition: TrainUnit.h:734
clStationStopBackground
#define clStationStopBackground
Definition: GraphicUnit.h:301
TInterface::AZOrderButton
TButton * AZOrderButton
Definition: InterfaceUnit.h:139
TInterface::SpeedButton86
TSpeedButton * SpeedButton86
Definition: InterfaceUnit.h:567
TInterface::SpeedButton122
TSpeedButton * SpeedButton122
Definition: InterfaceUnit.h:603
Crossover
@ Crossover
Definition: TrackUnit.h:63
TInterface::SpeedButton104
TSpeedButton * SpeedButton104
Definition: InterfaceUnit.h:585
TInterface::SignallerJoinedByMenuItem
TMenuItem * SignallerJoinedByMenuItem
Definition: InterfaceUnit.h:454
TRailGraphics::SpeedBut69NormBlackGlyph
Graphics::TBitmap * SpeedBut69NormBlackGlyph
Definition: GraphicUnit.h:1038
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:6226
TDisplay::ResetZoomInOffsets
void ResetZoomInOffsets()
Reset the zoomed-in screen display to the 'Home' position.
Definition: DisplayUnit.h:201
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:8415
TInterface::RotRightMenuItem
TMenuItem * RotRightMenuItem
Definition: InterfaceUnit.h:452
AtLocation
@ AtLocation
Definition: TrainUnit.h:67
TInterface::ExportTTButton
TButton * ExportTTButton
Definition: InterfaceUnit.h:147
DefaultTrackLength
#define DefaultTrackLength
Definition: TrackUnit.h:37
Signal
@ Signal
Definition: TrackUnit.h:72
TInterface::TimetableChangedFlag
bool TimetableChangedFlag
true when a timetable in the editor has changed (used to warn user if opts to exit without saving)
Definition: InterfaceUnit.h:951
TInterface::SaveTimetableToErrorFile
bool SaveTimetableToErrorFile(int Caller, std::ofstream &ErrorFile, AnsiString ErrorFileStr, AnsiString TimetableFileName)
Called when compiling the error log file, to save the loaded timetable if any and the timetable being...
Definition: InterfaceUnit.cpp:16097
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:677
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:15834
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:150
TInterface::TrainHeadCodeMenuItem
TMenuItem * TrainHeadCodeMenuItem
Definition: InterfaceUnit.h:436
TTrainController::TrainDataVector
TTrainDataVector TrainDataVector
vector containing the internal timetable
Definition: TrainUnit.h:775
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:10867
TTrain::ExitTimeHalf
TDateTime ExitTimeHalf
Definition: TrainUnit.h:409
Exited
@ Exited
Definition: TrainUnit.h:80
TInterface::OutputLog2
TLabel * OutputLog2
Definition: InterfaceUnit.h:272
TInterface::SpeedButton74
TSpeedButton * SpeedButton74
Definition: InterfaceUnit.h:555
TInterface::ScreenRightButtonClick
void __fastcall ScreenRightButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8114
TInterface::PositionalPanel
TPanel * PositionalPanel
Definition: InterfaceUnit.h:363
TInterface::StepForwardMenuItemClick
void __fastcall StepForwardMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9909
TInterface::ErrorLog
void ErrorLog(int Caller, AnsiString Message)
The error logging routine, called when an error is detected.
Definition: InterfaceUnit.cpp:15004
TInterface::SpeedButton50
TSpeedButton * SpeedButton50
Definition: InterfaceUnit.h:531
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackElement.at(At)
Definition: TrackUnit.cpp:8916
TTrainController::LoadSessionTrains
void LoadSessionTrains(int Caller, std::ifstream &SessionFile)
load trains from a session file
Definition: TrainUnit.cpp:13825
TInterface::SpeedButton31
TSpeedButton * SpeedButton31
Definition: InterfaceUnit.h:512
TInterface::UserGraphicFoundFlag
bool UserGraphicFoundFlag
indicates that a user graphic item has been found when clicking on a build screen for moving
Definition: InterfaceUnit.h:949
TInterface::RouteCancelButtonClick
void __fastcall RouteCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2085
TInterface::SpeedButton91
TSpeedButton * SpeedButton91
Definition: InterfaceUnit.h:572
TInterface::SelectedTrainID
int SelectedTrainID
used to store the train ID when right clicked for signaller control actions
Definition: InterfaceUnit.h:1016
TInterface::SpeedButton113
TSpeedButton * SpeedButton113
Definition: InterfaceUnit.h:594
TInterface::SpeedButton82
TSpeedButton * SpeedButton82
Definition: InterfaceUnit.h:563
TTextHandler::SelectTextPtrAt
TTextItem * SelectTextPtrAt(int Caller, int At)
return the text item at position 'At' in SelectTextVector (carries out range checking)
Definition: TextUnit.cpp:536
TInterface::SpeedButton132
TSpeedButton * SpeedButton132
Definition: InterfaceUnit.h:613
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:682
TInterface::FlashingGraphics
void FlashingGraphics(int Caller, TDateTime Now)
Deal with any warning graphics that need to flash (call on, signal stop, crash etc),...
Definition: InterfaceUnit.cpp:14454
TInterface::ScreenLeftButton
TBitBtn * ScreenLeftButton
Definition: InterfaceUnit.h:229
TTrain::StoppedAtLocation
bool StoppedAtLocation
Definition: TrainUnit.h:427
TTrainController::TContinuationTrainExpectationMultiMapIterator
TContinuationTrainExpectationMultiMap::iterator TContinuationTrainExpectationMultiMapIterator
iterator for the multimap
Definition: TrainUnit.h:680
TInterface::TTClockx16ButtonClick
void __fastcall TTClockx16ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11398
TInterface::BuildTrackMenuItem
TMenuItem * BuildTrackMenuItem
Definition: InterfaceUnit.h:397
TInterface::SaveOperatingImageMenuItem
TMenuItem * SaveOperatingImageMenuItem
Definition: InterfaceUnit.h:431
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:704
TInterface::NoRailway
bool NoRailway()
Returns true if there are no track elements and no text.
Definition: InterfaceUnit.cpp:17810
TInterface::AllEntriesTTListBox
TListBox * AllEntriesTTListBox
the list of service entries displayed on the left hand side of the timetable edit screen
Definition: InterfaceUnit.h:381
TInterface::CallingOnButtonClick
void __fastcall CallingOnButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8024
TInterface::SaveTTDialog
TSaveDialog * SaveTTDialog
Definition: InterfaceUnit.h:472
TInterface::DeleteOnePrefDirButtonClick
void __fastcall DeleteOnePrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1886
TTrack::WriteOperatingTrackToImage
void WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track element graphics to the image file in...
Definition: TrackUnit.cpp:3717
TAllRoutes::NextRouteID
int NextRouteID
stores the value for the route ID number that is next to be built
Definition: TrackUnit.h:1566
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success and re...
Definition: Utilities.cpp:467
TInterface::TTEntryChangedFlag
bool TTEntryChangedFlag
true when a timetable entry that is displayed in the timetable entry edit window has changed
Definition: InterfaceUnit.h:959
TInterface::HighlightPanel
TPanel * HighlightPanel
the red bar that displays the current timetable entry in AllEntriesTTListBox
Definition: InterfaceUnit.h:349
TInterface::SpeedButton16
TSpeedButton * SpeedButton16
Definition: InterfaceUnit.h:497
TInterface::MoveTTEntryUpButtonClick
void __fastcall MoveTTEntryUpButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4120
TInterface::SpeedBottomLabel
TLabel * SpeedBottomLabel
Definition: InterfaceUnit.h:180
TTrainController::BFHigh
bool BFHigh
Definition: TrainUnit.h:713
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TInterface::TTClockResetButtonClick
void __fastcall TTClockResetButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11571
TInterface::ClockLabel
TLabel * ClockLabel
the timetable clock
Definition: InterfaceUnit.h:300
TInterface::SpeedButton43
TSpeedButton * SpeedButton43
Definition: InterfaceUnit.h:524
TTrain::LagEntryPos
int LagEntryPos
Definition: TrainUnit.h:327
TInterface::SetTrackBuildImages
void SetTrackBuildImages(int Caller)
Sets the left screen images (track linked or not, gaps set or not, locations named or not) during rai...
Definition: InterfaceUnit.cpp:15231
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:3695
TInterface::AddText
@ AddText
Definition: InterfaceUnit.h:851
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2057
TTrainController::UnexpectedExits
int UnexpectedExits
Definition: TrainUnit.h:749
TInterface::LoadTimetableMenuItemClick
void __fastcall LoadTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9350
TInterface::LengthEditKeyUp
void __fastcall LengthEditKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11187
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:10648
TInterface::OutputLog1
TLabel * OutputLog1
Definition: InterfaceUnit.h:271
TTrain::LeavingUnderSigControlAtContinuation
bool LeavingUnderSigControlAtContinuation
set when the train has reached an exit continuation when under signaller control, used to prevent the...
Definition: TrainUnit.h:355
TInterface::SpeedButton84
TSpeedButton * SpeedButton84
Definition: InterfaceUnit.h:565
TInterface::SpeedButton77
TSpeedButton * SpeedButton77
Definition: InterfaceUnit.h:558
TInterface::SpeedButton128
TSpeedButton * SpeedButton128
Definition: InterfaceUnit.h:609
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:840
TInterface::AddSubMinsBox
TEdit * AddSubMinsBox
the edit box that accepts minutes to add or subtract
Definition: InterfaceUnit.h:174
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:17009
TInterface::TTClockExitButton
TButton * TTClockExitButton
Definition: InterfaceUnit.h:215
TInterface::SpeedEditBox2
TEdit * SpeedEditBox2
Definition: InterfaceUnit.h:100
TInterface::MoveForwardsMenuItemClick
void __fastcall MoveForwardsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9631
TTrack::Down
@ Down
Definition: TrackUnit.h:522
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set TempMarker true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:5836
TInterface::TimetableNameLabel
TLabel * TimetableNameLabel
displays the current timetable name on the timetable edit panel
Definition: InterfaceUnit.h:290
TInterface::SpeedButton79
TSpeedButton * SpeedButton79
Definition: InterfaceUnit.h:560
TInterface::SpeedBottomLabel2
TLabel * SpeedBottomLabel2
Definition: InterfaceUnit.h:111
TInterface::SpeedButton51
TSpeedButton * SpeedButton51
Definition: InterfaceUnit.h:532
TInterface::IsPerformancePanelObscuringFloatingLabel
bool IsPerformancePanelObscuringFloatingLabel(int Caller)
Checked during operation, returns true if so and PerformancePanel removed - not used from v2....
Definition: InterfaceUnit.cpp:15076
TimeTimeLoc
@ TimeTimeLoc
Definition: TrainUnit.h:62
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1386
TInterface::TimetableChangedInAZOrderFlag
bool TimetableChangedInAZOrderFlag
used to give a warning message that changes will be discarded if proceed
Definition: InterfaceUnit.h:955
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement.
Definition: TrackUnit.cpp:5943
TInterface::AddTrackButtonClick
void __fastcall AddTrackButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:836
TInterface::SpeedButton92
TSpeedButton * SpeedButton92
Definition: InterfaceUnit.h:573
TInterface::DeleteMenuItemClick
void __fastcall DeleteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9212
TTrain::Derailed
bool Derailed
Definition: TrainUnit.h:427
TTextHandler::TextVectorPush
void TextVectorPush(int Caller, TTextItem Text)
push &Text onto TextVector & reset the size of the railway if necessary
Definition: TextUnit.cpp:479
TInterface::TTClockAdjButton
TBitBtn * TTClockAdjButton
Definition: InterfaceUnit.h:203
TInterface::PowerEditBoxKeyUp
void __fastcall PowerEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11054
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:15479
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:6299
TTrainController::SaveSessionLockedRoutes
void SaveSessionLockedRoutes(int Caller, std::ofstream &SessionFile)
save locked routes to a session file
Definition: TrainUnit.cpp:13875
TInterface::OpenHelpMenuItemClick
void __fastcall OpenHelpMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10789
TTextHandler::TextFound
bool TextFound(int Caller, int HPosInput, int VPosInput)
look for a text item in the vicinity of HPosInput & VPosInput & return true if found
Definition: TextUnit.cpp:225
TTrain::OriginalPowerAtRail
double OriginalPowerAtRail
new at v2.4.0 to store value before a failure so it can be restored from here when repaired
Definition: TrainUnit.h:396
TInterface::CheckPerformanceFile
bool CheckPerformanceFile(int Caller, std::ifstream &InFile)
Check the performance file embedded within a session file & return false for error,...
Definition: InterfaceUnit.cpp:17059
TInterface::TInterface
__fastcall TInterface(TComponent *Owner)
constructor
Definition: InterfaceUnit.cpp:79
TInterface::SpeedButton15
TSpeedButton * SpeedButton15
Definition: InterfaceUnit.h:496
clB4G5R5
#define clB4G5R5
Definition: GraphicUnit.h:244
Timetable
@ Timetable
Definition: TrainUnit.h:56
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:122
TInterface
Definition: InterfaceUnit.h:55
TInterface::RemoveTrainMenuItemClick
void __fastcall RemoveTrainMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9953
TInterface::RotRightMenuItemClick
void __fastcall RotRightMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8821
TTrain::AbleToMoveButForSignal
bool AbleToMoveButForSignal(int Caller)
Indicates that a train is only prevented from moving by a signal - used to allow appropriate popup me...
Definition: TrainUnit.cpp:6289
TTrainController::OpActionPanelVisible
bool OpActionPanelVisible
new v2.2.0 flag to prevent time to act functions when not visible
Definition: TrainUnit.h:710
TInterface::SaveInterface
void SaveInterface(int Caller, std::ofstream &SessionFile)
Save interface part of a session file.
Definition: InterfaceUnit.cpp:15684
TInterface::AcceptDragging
void __fastcall AcceptDragging(TObject *Sender, TObject *Source, int X, int Y, TDragState State, bool &Accept)
Definition: InterfaceUnit.cpp:5372
Parapet
@ Parapet
Definition: TrackUnit.h:65
TTrack::GapFlashRedPosition
int GapFlashRedPosition
TrackVectorPosition of the gap element that is flashing green or red.
Definition: TrackUnit.h:668
HiddenDisplay
TDisplay * HiddenDisplay
The object pointer for the internal hidden display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:55
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:15504
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:64
TInterface::RouteFlashDuration
float RouteFlashDuration
duration of the route flash period
Definition: InterfaceUnit.h:975
TInterface::SpeedButton4
TSpeedButton * SpeedButton4
Definition: InterfaceUnit.h:485
TTrainController::SignalStopWarning
bool SignalStopWarning
Definition: TrainUnit.h:702
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:276
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7682
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:15454
TDisplay::PerformanceLog
void PerformanceLog(int Caller, AnsiString Statement)
Send Statement to the performance log on screen and to the file.
Definition: DisplayUnit.cpp:448
TTrain::SignallerStopBrakeRate
double SignallerStopBrakeRate
the train brake rate when stopping under signaller control
Definition: TrainUnit.h:391
TTrainController::SignallerTrainRemovedOnAutoSigsRoute
bool SignallerTrainRemovedOnAutoSigsRoute
true if train was on an AutoSigsRoute when removed by the signaller
Definition: TrainUnit.h:708
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:705
TTrainController::MRSLow
bool MRSLow
Definition: TrainUnit.h:713
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
map of active track element names
Definition: TrackUnit.h:680
TTrain::Crashed
bool Crashed
Definition: TrainUnit.h:427
TInterface::SpeedButton44
TSpeedButton * SpeedButton44
Definition: InterfaceUnit.h:525
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:144
TInterface::ScreenRightButton
TBitBtn * ScreenRightButton
Definition: InterfaceUnit.h:228
TTrain::HeadCodePosition
Graphics::TBitmap * HeadCodePosition[4]
Set from the HeadCodeGrPtr[4] pointer values, HeadCodePosition[0] is always the front,...
Definition: TrainUnit.h:441
TInterface::SigPrefButtonClick
void __fastcall SigPrefButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2011
TInterface::OAListBox
TListBox * OAListBox
Operator action list, sits inside OperatorActionPanel and lists trains in ascending order of time to ...
Definition: InterfaceUnit.h:383
TTrain::TrainID
int TrainID
the train's identification number
Definition: TrainUnit.h:330
TInterface::SaveTTButton
TButton * SaveTTButton
Definition: InterfaceUnit.h:144
TUtilities::CheckStringDouble
bool CheckStringDouble(AnsiString &DoubleString)
checks the string represents a valid double value, returns true for success. Added at v2....
Definition: Utilities.cpp:326
TInterface::SpeedButton63
TSpeedButton * SpeedButton63
Definition: InterfaceUnit.h:544
TRailGraphics::bmLightBlueRect
Graphics::TBitmap * bmLightBlueRect
Definition: GraphicUnit.h:522
TInterface::NonSigRouteStartMarker
TGraphicElement * NonSigRouteStartMarker
Definition: InterfaceUnit.h:1054
clB3G3R3
#define clB3G3R3
Definition: GraphicUnit.h:186
TInterface::SpeedButton53
TSpeedButton * SpeedButton53
Definition: InterfaceUnit.h:534
TInterface::SpeedButton107
TSpeedButton * SpeedButton107
Definition: InterfaceUnit.h:588
TTrainController::TrainVectorAt
TTrain & TrainVectorAt(int Caller, int VecPos)
Return a reference to the train at position VecPos in the TrainVector, carries out range checking on ...
Definition: TrainUnit.cpp:14151
TInterface::EditMenuClick
void __fastcall EditMenuClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8489
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:10575
TInterface::ModeMenu
TMenuItem * ModeMenu
Definition: InterfaceUnit.h:396
TInterface::SpeedButton112
TSpeedButton * SpeedButton112
Definition: InterfaceUnit.h:593
TInterface::MTBFEditBoxClick
void __fastcall MTBFEditBoxClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11882
TInterface::TEVPtr
TTEVPtr TEVPtr
Definition: InterfaceUnit.h:1077
TInterface::MasterClock
TTimer * MasterClock
the program clock (not the timetable clock)
Definition: InterfaceUnit.h:476
TInterface::OutputLog6MouseDown
void __fastcall OutputLog6MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10718
TRailGraphics::SpeedBut70GrndBlackGlyph
Graphics::TBitmap * SpeedBut70GrndBlackGlyph
Definition: GraphicUnit.h:1047
TTrainController::NumFailures
int NumFailures
Definition: TrainUnit.h:750
TInterface::CreateEditTTTitle
AnsiString CreateEditTTTitle
the title of the timetable currently being edited - i.e. the filename without the '....
Definition: InterfaceUnit.h:872
TInterface::AboutMenuItemClick
void __fastcall AboutMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10768
TInterface::SelectStartPair
THVPair SelectStartPair
'Select' menu items
Definition: InterfaceUnit.h:1056
TTrainController::TOpTimeToActMultiMapIterator
TOpTimeToActMultiMap::iterator TOpTimeToActMultiMapIterator
Definition: TrainUnit.h:695
TInterface::SpeedButton6
TSpeedButton * SpeedButton6
Definition: InterfaceUnit.h:487
TTrack
Definition: TrackUnit.h:462
TInterface::OperatorActionPanelStartDrag
void __fastcall OperatorActionPanelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:5447
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:752
TInterface::OperateRailwayMenuItem
TMenuItem * OperateRailwayMenuItem
Definition: InterfaceUnit.h:401
TInterface::SaveRailwayTBPButton
TBitBtn * SaveRailwayTBPButton
Save button on TrackBuildPanel.
Definition: InterfaceUnit.h:72
TTrain::ExitSpeedFull
double ExitSpeedFull
speed when leaving the next element
Definition: TrainUnit.h:379
TInterface::MTBFLabel
TLabel * MTBFLabel
Definition: InterfaceUnit.h:459
TInterface::SelectBitmap
Graphics::TBitmap * SelectBitmap
the graphic defined by Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:980
TInterface::PreventGapOffsetResetting
bool PreventGapOffsetResetting
during gap setting gaps are highlighted in turn for the user to select the matching gap,...
Definition: InterfaceUnit.h:921
TInterface::TakeSignallerControlMenuItem
TMenuItem * TakeSignallerControlMenuItem
Definition: InterfaceUnit.h:437
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TInterface::Pasting
@ Pasting
Definition: InterfaceUnit.h:852
TInterface::AddTextButton
TBitBtn * AddTextButton
Definition: InterfaceUnit.h:65
TInterface::LoadRailwayMenuItem
TMenuItem * LoadRailwayMenuItem
Definition: InterfaceUnit.h:387
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:72
TInterface::CrashImage
TImage * CrashImage
Definition: InterfaceUnit.h:242
TTrainController::RandomFailureCounter
unsigned int RandomFailureCounter
Definition: TrainUnit.h:765
TInterface::SpeedButton123
TSpeedButton * SpeedButton123
Definition: InterfaceUnit.h:604
TInterface::USERGRAPHICS_DIR_NAME
static const UnicodeString USERGRAPHICS_DIR_NAME
Definition: InterfaceUnit.h:838
TInterface::mbLeftDown
bool mbLeftDown
true when the left mouse button is down
Definition: InterfaceUnit.h:913
TInterface::SpeedButton115
TSpeedButton * SpeedButton115
Definition: InterfaceUnit.h:596
TInterface::ProgramVersion
UnicodeString ProgramVersion
Definition: InterfaceUnit.h:824
TInterface::TTClockResetButton
TButton * TTClockResetButton
Definition: InterfaceUnit.h:216
TUtilities::CheckAndReadFileInt
bool CheckAndReadFileInt(std::ifstream &InFile, int Lowest, int Highest, int &OutInt)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success ...
Definition: Utilities.cpp:250
TInterface::TempCursor
TCursor TempCursor
stores the screen cursor while a temporary cursor (ususlly an hourglass) is displayed
Definition: InterfaceUnit.h:1043
Interface
TInterface * Interface
Definition: InterfaceUnit.cpp:66
TInterface::SpeedButton61
TSpeedButton * SpeedButton61
Definition: InterfaceUnit.h:542
TDisplay::HideWarningLog
void HideWarningLog(int Caller)
Hide all the warnings from the top part of the screen - for timetable clock adjustment.
Definition: DisplayUnit.cpp:476
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:125
TUtilities::DecimalPoint
char DecimalPoint
added at v2.4.0 so can use the local value in loaded session files
Definition: Utilities.h:44
TInterface::ConstructPrefDir
TOnePrefDir * ConstructPrefDir
the Pref Dir under construction
Definition: InterfaceUnit.h:1063
TInterface::SpeedButton81
TSpeedButton * SpeedButton81
Definition: InterfaceUnit.h:562
TInterface::SigsOnLeftImage1
TImage * SigsOnLeftImage1
Definition: InterfaceUnit.h:259
TInterface::BuildTrackMenuItemClick
void __fastcall BuildTrackMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:819
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2595
TInterface::ClearandRebuildRailway
void ClearandRebuildRailway(int Caller)
Clear screen and rebuild it from stored data, uses HiddenScreen to avoid flicker.
Definition: InterfaceUnit.cpp:11980
TInterface::DisplayOneTTLineInPanel
void DisplayOneTTLineInPanel(int Caller, AnsiString Data, bool ServiceEntry)
Display a line from the TimetableEditVector (consists of a series of AnsiStrings, each of which repre...
Definition: InterfaceUnit.cpp:5152
TInterface::PlanPrefDirsMenuItem
TMenuItem * PlanPrefDirsMenuItem
Definition: InterfaceUnit.h:398
TInterface::AreAnyTimesInCurrentEntry
bool AreAnyTimesInCurrentEntry()
Search the timetable entry pointed to by TTCurrentEntryPtr and if any times (HH:MM) are present retur...
Definition: InterfaceUnit.cpp:5232
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:7797
TInterface::AutoRouteStartMarker
TGraphicElement * AutoRouteStartMarker
Definition: InterfaceUnit.h:1054
TInterface::RestoreTTButtonClick
void __fastcall RestoreTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4281
TInterface::SaveTTButtonClick
void __fastcall SaveTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3923
TInterface::FormCreate
void __fastcall FormCreate(TObject *Sender)
Definition: InterfaceUnit.cpp:715
TGraphicElement::SetSourceRect
void SetSourceRect(int Left, int Top)
Set SourceRect member values from those supplied and existing Width & Height - ensure this is only ca...
Definition: TrackUnit.h:372
TTrack::SelectPush
void SelectPush(TTrackElement TrackElement)
Store a TrackElement in the SelectVector.
Definition: TrackUnit.h:819
TAllRoutes::SignallerRemovedTrainAutoRoute
TOneRoute SignallerRemovedTrainAutoRoute
if train was on an AutoSigsRoute when removed then this stores the route so that signals can be reset
Definition: TrackUnit.h:1572
TInterface::SpeedButton7
TSpeedButton * SpeedButton7
Definition: InterfaceUnit.h:488
TTrainController::MassHigh
bool MassHigh
Definition: TrainUnit.h:713
TInterface::TimetablePanel
TPanel * TimetablePanel
'Create a timetable'/'Edit a timetable' panel that contains the topmost buttons (show/hide & exit)
Definition: InterfaceUnit.h:340
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:1822
TTrain::PlotTrainWithNewBackgroundColour
void PlotTrainWithNewBackgroundColour(int Caller, TColor NewBackgroundColour, TDisplay *Disp)
Changes the train's background colour (e.g. to pale green if stopped at a station) Note that this use...
Definition: TrainUnit.cpp:3256
TInterface::LoadSessionMenuItem
TMenuItem * LoadSessionMenuItem
Definition: InterfaceUnit.h:391
TInterface::SpeedButton69
TSpeedButton * SpeedButton69
Definition: InterfaceUnit.h:550
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:130
TInterface::OutputLog5MouseDown
void __fastcall OutputLog5MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10709
TInterface::ErrorButton
TBitBtn * ErrorButton
the 'Press to exit' button on the error screen
Definition: InterfaceUnit.h:236
TInterface::SpeedButton24
TSpeedButton * SpeedButton24
Definition: InterfaceUnit.h:505
TInterface::WarningFlash
bool WarningFlash
toggles on and off automatically at a cycle of about 0.5 sec, used to drive the warning icons during ...
Definition: InterfaceUnit.h:961
TInterface::CurrentSpeedButton
TSpeedButton * CurrentSpeedButton
stores the selected track build element button during railway building
Definition: InterfaceUnit.h:1074
TInterface::MainScreenMouseDown
void __fastcall MainScreenMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:5468
TTrain::ExitTimeFull
TDateTime ExitTimeFull
times used in SetTrainMovementValues corresponding to the next element the train runs on
Definition: TrainUnit.h:409
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:155
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:688
TInterface::TotalTicks
unsigned int TotalTicks
total clock ticks
Definition: InterfaceUnit.h:986
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2280
TInterface::SpeedTopLabel2
TLabel * SpeedTopLabel2
Definition: InterfaceUnit.h:110
SignallerChangeDirection
@ SignallerChangeDirection
Definition: TrainUnit.h:51
TRailGraphics::GridBitmap
Graphics::TBitmap * GridBitmap
Definition: GraphicUnit.h:892
TInterface::PowerBottomLabel
TLabel * PowerBottomLabel
Definition: InterfaceUnit.h:188
TInterface::PasteMenuItem
TMenuItem * PasteMenuItem
Definition: InterfaceUnit.h:414
TTextHandler::EnterAndDisplayNewText
void EnterAndDisplayNewText(int Caller, TTextItem Text, int HPos, int VPos)
add Text to TextVector and display it on the screen
Definition: TextUnit.cpp:179
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:10363
TInterface::CreateEditTTFileName
AnsiString CreateEditTTFileName
the full path and filename of the timetable file
Definition: InterfaceUnit.h:870
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:11120
TInterface::PerformanceLogButtonClick
void __fastcall PerformanceLogButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2107
TTrainController::CheckSessionContinuationAutoSigEntries
bool CheckSessionContinuationAutoSigEntries(int Caller, std::ifstream &SessionFile)
Part of the session file integrity check for ContinuationAutoSigEntries, true for success.
Definition: TrainUnit.cpp:13997
IDInt
Definition: TrackUnit.h:411
TInterface::SelectLengthsMenuItemClick
void __fastcall SelectLengthsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9231
TInterface::NewSelectBitmapHLoc
int NewSelectBitmapHLoc
the new (during & at end of moving) HLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:992
TInterface::LoadUserGraphic
void LoadUserGraphic(int Caller)
Load a user-defined graphic (bmp, gif, jpg, png).
Definition: InterfaceUnit.cpp:18037
TInterface::TTCurrentEntryPtr
TTEVPtr TTCurrentEntryPtr
Definition: InterfaceUnit.h:1077
TRunningEntry
TRunningEntry
contains status info for each train
Definition: TrainUnit.h:79
TInterface::OutputLog6
TLabel * OutputLog6
Definition: InterfaceUnit.h:276
TUtilities
Definition: Utilities.h:35
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:3964
TInterface::CreateTimetableMenuItemClick
void __fastcall CreateTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2971
TInterface::ExportTTButtonClick
void __fastcall ExportTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4364
TDisplay
Definition: DisplayUnit.h:48
TInterface::SpeedButton9
TSpeedButton * SpeedButton9
Definition: InterfaceUnit.h:490
TInterface::TTClockxEighthButtonClick
void __fastcall TTClockxEighthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11474
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:8663
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:142
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:767
TInterface::Text_X
int Text_X
the 'X' pixel value for an item of text
Definition: InterfaceUnit.h:1026
TInterface::SpeedVariableLabel
TLabel * SpeedVariableLabel
Definition: InterfaceUnit.h:181
TInterface::SpeedButton49
TSpeedButton * SpeedButton49
Definition: InterfaceUnit.h:530
TTrain::StoppedWithoutPower
bool StoppedWithoutPower
Definition: TrainUnit.h:428
TInterface::PowerVariableLabel
TLabel * PowerVariableLabel
Definition: InterfaceUnit.h:189
TActionEventType
TActionEventType
Used for reporting error conditions & warnings.
Definition: TrainUnit.h:39
TInterface::GapsNotSetImage
TImage * GapsNotSetImage
Definition: InterfaceUnit.h:256
TInterface::Level1Mode
enum TInterface::TLevel1Mode Level1Mode
TInterface::CallLogTickerLabel
TLabel * CallLogTickerLabel
diagnostic label displaying the call log depth, made visible by ctrl+ alt+ 2
Definition: InterfaceUnit.h:298
TInterface::TimetableEditVector
TTimetableEditVector TimetableEditVector
Definition: InterfaceUnit.h:1080
TTrainController::TrainExistsAtIdent
bool TrainExistsAtIdent(int Caller, int TrainID)
new at v2.4.0 return true if find the train (added at v2.4.0 as can select a removed train in OAListB...
Definition: TrainUnit.cpp:8497
SignallerJoin
@ SignallerJoin
Definition: TrainUnit.h:50
TTrain::StepForwardFlag
bool StepForwardFlag
set when the signaller command to step forward one element has been given
Definition: TrainUnit.h:363
TInterface::SaveRailwayDialog
TSaveDialog * SaveRailwayDialog
Definition: InterfaceUnit.h:471
TInterface::TrainTTInfoOnOffMenuItemClick
void __fastcall TrainTTInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5347
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:94
TTrainController::Operate
void Operate(int Caller)
called every clock tick to introduce new trains and update existing trains
Definition: TrainUnit.cpp:7809
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:150
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:878
TTrain::PowerAtRail
double PowerAtRail
in Watts (taken as 80% of the train's Gross Power, i.e. that entered by the user)
Definition: TrainUnit.h:394
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:666
TAllRoutes::LevelCrossingBarrierDownDelay
const float LevelCrossingBarrierDownDelay
the full value in seconds for which the level crossing flashes prior to opening to trains
Definition: TrackUnit.h:1560
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1553
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:153
TInterface::SetSaveMenuAndButtons
void SetSaveMenuAndButtons(int Caller)
Called during the ClockTimer2 function to set screen boundaries, buttons & menu items.
Definition: InterfaceUnit.cpp:14711
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TInterface::TIMETABLE_DIR_NAME
static const UnicodeString TIMETABLE_DIR_NAME
Definition: InterfaceUnit.h:833
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:127
TInterface::SaveImageAndPrefDirsMenuItem
TMenuItem * SaveImageAndPrefDirsMenuItem
Definition: InterfaceUnit.h:430
TInterface::LoadRailwayMenuItemClick
void __fastcall LoadRailwayMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2190
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:6543
TInterface::FormKeyUp
void __fastcall FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:10659
TTrainDataEntry::TrainOperatingDataVector
TTrainOperatingDataVector TrainOperatingDataVector
operating information for the train including all its repeats
Definition: TrainUnit.h:197
TInterface::OutputLog9MouseDown
void __fastcall OutputLog9MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10748
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:543
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:144
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:786
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1372
TInterface::SpeedButton80
TSpeedButton * SpeedButton80
Definition: InterfaceUnit.h:561
TTrain::IsThereAnAdjacentTrain
bool IsThereAnAdjacentTrain(int Caller, TTrain *&TrainToBeJoinedBy)
Definition: TrainUnit.cpp:4703
TInterface::ApproachLocking
void ApproachLocking(int Caller, TDateTime Now)
Function that deals with approach locking during ClockTimer2 function.
Definition: InterfaceUnit.cpp:13721
TInterface::TimetableTitle
AnsiString TimetableTitle
the titles of the loaded railway and loaded timetable, i.e. the filenames without the extension
Definition: InterfaceUnit.h:884
TInterface::BlackBgndMenuItemClick
void __fastcall BlackBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10812
TInterface::SpeedButton114
TSpeedButton * SpeedButton114
Definition: InterfaceUnit.h:595
TInterface::Deleting
@ Deleting
Definition: InterfaceUnit.h:852
TInterface::RestoreAllDefaultLengthsButton
TBitBtn * RestoreAllDefaultLengthsButton
Definition: InterfaceUnit.h:76
TInterface::ClearAllMenuItemClick
void __fastcall ClearAllMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2901
TUtilities::EventLog
std::deque< AnsiString > EventLog
event store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:56
TActionVectorEntry::FormatType
TTimetableFormatType FormatType
defines the timetable action type
Definition: TrainUnit.h:110
TInterface::TextBox
TEdit * TextBox
the edit box that accepts text to be added
Definition: InterfaceUnit.h:87
TGraphicElement::GetHPos
int GetHPos()
Definition: TrackUnit.h:361
TInterface::SpeedButton133
TSpeedButton * SpeedButton133
Definition: InterfaceUnit.h:614
TOnePrefDir::SearchVectorSize
unsigned int SearchVectorSize() const
Return the vector size.
Definition: TrackUnit.h:1265
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:637
TTrainController::TimetableStartTime
TDateTime TimetableStartTime
the start time of the current timetable
Definition: TrainUnit.h:635
TTrainController::UnplotTrains
void UnplotTrains(int Caller)
unplot all trains from screen
Definition: TrainUnit.cpp:8152
TInterface::SpeedButton18
TSpeedButton * SpeedButton18
Definition: InterfaceUnit.h:499
TInterface::ScreenGridFlag
bool ScreenGridFlag
true when the screen grid is displayed
Definition: InterfaceUnit.h:929
TInterface::InfoCaptionStore
AnsiString InfoCaptionStore
temporary store for the information panel caption
Definition: InterfaceUnit.h:878
TRailGraphics::smBrightGreen
Graphics::TBitmap * smBrightGreen
Definition: GraphicUnit.h:870
TInterface::CopiedEntryFlag
bool CopiedEntryFlag
true when CopiedEntryStr holds a timetable entry in the timetable editor
Definition: InterfaceUnit.h:901
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:13475
TInterface::SpeedButton89
TSpeedButton * SpeedButton89
Definition: InterfaceUnit.h:570
TTrainController::EarlyArrivals
int EarlyArrivals
Definition: TrainUnit.h:735
TTrainController::CreateFormattedTimetable
void CreateFormattedTimetable(int Caller, AnsiString RailwayTitle, AnsiString TimetableTitle, AnsiString CurDir)
Examines the internal timetable (TrainDataVector) and creates from it a chronological (....
Definition: TrainUnit.cpp:14164
TTrack::RouteFlashFlag
bool RouteFlashFlag
true while a route is flashing prior to being set
Definition: TrackUnit.h:656
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:11579
TInterface::PowerToggleButtonClick
void __fastcall PowerToggleButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11033
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1170
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:148
TInterface::SpeedButton46
TSpeedButton * SpeedButton46
Definition: InterfaceUnit.h:527
Points
@ Points
Definition: TrackUnit.h:63
TTrainController::TotLatePassMins
float TotLatePassMins
Definition: TrainUnit.h:730
TTrainController::StripSpaces
void StripSpaces(int Caller, AnsiString &Input)
Strip both leading and trailing spaces at ends of Input and spaces before and after all commas and se...
Definition: TrainUnit.cpp:12561
TInterface::Delay
void Delay(int Caller, double Msec)
Delays operation for the set time in milliseconds.
Definition: InterfaceUnit.cpp:12343
TTrain::JoinedOtherTrainFlag
bool JoinedOtherTrainFlag
true when the train has joined another train following an 'Fjo' timetable command or a signaller join...
Definition: TrainUnit.h:351
TTrainController::OpActionPanelHintDelayCounter
unsigned int OpActionPanelHintDelayCounter
new v2.2.0 on start operation delays the op action panel headcode display for about 5 secs while hint...
Definition: TrainUnit.h:763
TTrainController::BFLow
bool BFLow
Definition: TrainUnit.h:713
TInterface::OutputLog7
TLabel * OutputLog7
Definition: InterfaceUnit.h:277
TTrainController::TotArrDepPass
int TotArrDepPass
Definition: TrainUnit.h:748
TInterface::LastNonCtrlOrShiftKeyDown
int LastNonCtrlOrShiftKeyDown
value of last key (other than Ctrl or Shift) pressed down - to prevent repeated FormKeyDown calls fro...
Definition: InterfaceUnit.h:990
SignallerPassRedSignal
@ SignallerPassRedSignal
Definition: TrainUnit.h:51
TRailGraphics::ChangeForegroundColour
void ChangeForegroundColour(int Caller, Graphics::TBitmap *BitmapIn, Graphics::TBitmap *BitmapOut, TColor NewForegroundColour, TColor BackgroundColour)
Definition: GraphicUnit.cpp:3290
TInterface::TextItem
int TextItem
used to store a single item of text
Definition: InterfaceUnit.h:1032
TInterface::UserGraphicButtonClick
void __fastcall UserGraphicButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11904
TInterface::OriginalTimetableEditVector
TTimetableEditVector OriginalTimetableEditVector
the complete timetable as a list of AnsiStrings for use in edit timetable functions
Definition: InterfaceUnit.h:1080
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1568
TInterface::PresetAutoSigRoutesButtonClick
void __fastcall PresetAutoSigRoutesButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11612
TRailGraphics::SpeedBut68GrndBlackGlyph
Graphics::TBitmap * SpeedBut68GrndBlackGlyph
Definition: GraphicUnit.h:1045
TTrain::SignallerRemoved
bool SignallerRemoved
set when removed under signaller control to force a removal from the display at the next clock tick
Definition: TrainUnit.h:359
TTrain::FrontCodePtr
Graphics::TBitmap * FrontCodePtr
points to the front headcode segment, this is set to red or blue depending on TrainMode
Definition: TrainUnit.h:445
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:14814
Continuation
@ Continuation
Definition: TrackUnit.h:63
TInterface::ScreenUpButton
TBitBtn * ScreenUpButton
Definition: InterfaceUnit.h:230
TInterface::TTServiceSyntaxCheckButton
TButton * TTServiceSyntaxCheckButton
Definition: InterfaceUnit.h:142
TTrainController::CallOnWarning
bool CallOnWarning
Definition: TrainUnit.h:702
TInterface::SetLengthsButton
TBitBtn * SetLengthsButton
Definition: InterfaceUnit.h:70
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
GraphicUnit.h
TInterface::AppActivate
void __fastcall AppActivate(TObject *Sender)
Definition: InterfaceUnit.cpp:766
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3325
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:5344
TInterface::AddTextButtonClick
void __fastcall AddTextButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:975
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:86
TInterface::ReselectMenuItemClick
void __fastcall ReselectMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8532
TInterface::SpeedButton94
TSpeedButton * SpeedButton94
Definition: InterfaceUnit.h:575
TInterface::SaveTTEntryButtonClick
void __fastcall SaveTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3775
TInterface::TimetablePanelLabel
TLabel * TimetablePanelLabel
label to the left of TimetablePanel
Definition: InterfaceUnit.h:292
TTrack::PointFlashFlag
bool PointFlashFlag
true when points are flashing during manual change
Definition: TrackUnit.h:654
TTrainController::OnTimeDeps
int OnTimeDeps
Definition: TrainUnit.h:743
TTrain::RestoreTimetableLocation
AnsiString RestoreTimetableLocation
stores the location name at which signaller control is taken, to ensure that it is back at that locat...
Definition: TrainUnit.h:419
TInterface::SpeedButton40
TSpeedButton * SpeedButton40
Definition: InterfaceUnit.h:521
TTrainController::TimetableIntegrityCheck
bool TimetableIntegrityCheck(int Caller, char *FileName, bool GiveMessages, bool CheckLocationsExistInRailway)
Checks overall timetable integrity, calls many other specific checking functions, returns true for su...
Definition: TrainUnit.cpp:8787
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TDisplay::Left
int Left()
Return the left pixel position of the screen.
Definition: DisplayUnit.h:114
TTrain::SignallerMaxSpeed
int SignallerMaxSpeed
maximum train speed under signaller control (in km/h)
Definition: TrainUnit.h:323
TInterface::BufferAttentionImage
TImage * BufferAttentionImage
Definition: InterfaceUnit.h:240
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:10406
TTrainController::SendPerformanceSummary
void SendPerformanceSummary(int Caller, std::ofstream &PerfFile)
At the end of operation a summary of overall performance is sent to the performance file by this func...
Definition: TrainUnit.cpp:14798
TInterface::OperatorActionButtonClick
void __fastcall OperatorActionButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11716
TInterface::SpeedEditBox
TEdit * SpeedEditBox
Definition: InterfaceUnit.h:178
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition)
look for a text item in the vicinity of HPosInput & VPosInput & erase it if found
Definition: TextUnit.cpp:249
TInterface::LoadRailwayDialog
TOpenDialog * LoadRailwayDialog
Definition: InterfaceUnit.h:465
TInterface::CopyMenuItem
TMenuItem * CopyMenuItem
Definition: InterfaceUnit.h:410
TInterface::ResetDefaultLengthButtonClick
void __fastcall ResetDefaultLengthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1484
RepairFailedTrain
@ RepairFailedTrain
Definition: TrainUnit.h:51
TInterface::NoOperMode
@ NoOperMode
Definition: InterfaceUnit.h:843
TInterface::ErrorLogCalledFlag
bool ErrorLogCalledFlag
true when an error has been thrown, stops repeated calls to ErrorLog and stops the MasterClockTimer f...
Definition: InterfaceUnit.h:907
TInterface::RouteFlashStartTime
TDateTime RouteFlashStartTime
stores the starting time (timetable clock time) for route flashing
Definition: InterfaceUnit.h:1050
TInterface::PerformancePanelLabel
TLabel * PerformancePanelLabel
label at the top of PerformancePanel
Definition: InterfaceUnit.h:282
TInterface::BlueBgndMenuItemClick
void __fastcall BlueBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10887
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, bool ConsecSignals, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:6090
TInterface::SetTrackLengths
void SetTrackLengths(int Caller, int Distance, int SpeedLimit)
Called during track building when setting distances, to calculate and set the individual track elemen...
Definition: InterfaceUnit.cpp:17481
TInterface::SpeedToggleButtonClick
void __fastcall SpeedToggleButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10924
TTrainController::ContinuationEntryFloatingTTString
AnsiString ContinuationEntryFloatingTTString(int Caller, TTrainDataEntry *TTDEPtr, int RepeatNumber, int IncrementalMinutes, int IncrementalDigits)
Build string for use in floating window for expected trains at continuations.
Definition: TrainUnit.cpp:8528
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:2961
TGraphicElement::GetVPos
int GetVPos()
Definition: TrackUnit.h:366
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1389
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:84
TTrain::SPADFlag
bool SPADFlag
set when running past a red signal without permission flags to indicate relevant stop conditions or p...
Definition: TrainUnit.h:425
TInterface::TTLabel5
TLabel * TTLabel5
Definition: InterfaceUnit.h:322
TInterface::HomeButtonClick
void __fastcall HomeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8420
TInterface::PointFlashStartTime
TDateTime PointFlashStartTime
stores the starting time (timetable clock time) for points flashing
Definition: InterfaceUnit.h:1048
TInterface::TTLabel7
TLabel * TTLabel7
Definition: InterfaceUnit.h:324
TInterface::RailwayWebSiteMenuItemClick
void __fastcall RailwayWebSiteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10804
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:607
TInterface::SpeedButton36
TSpeedButton * SpeedButton36
Definition: InterfaceUnit.h:517
TInterface::TTFirstServicePtr
TTEVPtr TTFirstServicePtr
Definition: InterfaceUnit.h:1077
TInterface::ClockTimer2
void ClockTimer2(int Caller)
The main loop, called every clock tick via MasterClockTimer.
Definition: InterfaceUnit.cpp:7581
TInterface::SpeedButton56
TSpeedButton * SpeedButton56
Definition: InterfaceUnit.h:537
TDisplay::PlotDashedRect
void PlotDashedRect(int Caller, TRect Rect)
Plot a dashed rectangle for the area defined by Rect, used when selecting display areas.
Definition: DisplayUnit.cpp:430
TInterface::NewTTEntryButtonClick
void __fastcall NewTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3350
TInterface::LoadSessionMenuItemClick
void __fastcall LoadSessionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2887
TTrack::SelectVectorClear
void SelectVectorClear()
Definition: TrackUnit.h:824
TInterface::PerformanceFileName
AnsiString PerformanceFileName
full path and filename of the performance file
Definition: InterfaceUnit.h:882
TInterface::AutoSigsButton
TBitBtn * AutoSigsButton
Definition: InterfaceUnit.h:194
TInterface::PopupMenu
TPopupMenu * PopupMenu
Definition: InterfaceUnit.h:462
TInterface::LoadSessionFlag
bool LoadSessionFlag
true when a session load command has been given - implemented at next clock tick
Definition: InterfaceUnit.h:911
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:270
TInterface::NoTrackMode
@ NoTrackMode
Definition: InterfaceUnit.h:851
TInterface::TimetableValidFlag
bool TimetableValidFlag
indicates that a 'Validate timetable' button click in the timetable editor has succeeded
Definition: InterfaceUnit.h:953
TInterface::TimetableControlMenuItem
TMenuItem * TimetableControlMenuItem
Definition: InterfaceUnit.h:438
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:293
TUtilities::PerformanceFile
std::ofstream PerformanceFile
the file where the performance log for a particular period of operation is saved
Definition: Utilities.h:52
TInterface::TTLabel15
TLabel * TTLabel15
Definition: InterfaceUnit.h:331
TInterface::PreferredRoute
bool PreferredRoute
true when AutoSig or preferred route building selected during operation (always same state as ConsecS...
Definition: InterfaceUnit.h:917
TInterface::ConvertCRLFsToCommas
void ConvertCRLFsToCommas(int Caller, AnsiString &ConvStr)
Used in timetable editing functions to convert any CRLFs in intended service entries to commas.
Definition: InterfaceUnit.cpp:4935
TInterface::OutputLog2MouseDown
void __fastcall OutputLog2MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10680
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:84
TInterface::SpeedButton106
TSpeedButton * SpeedButton106
Definition: InterfaceUnit.h:587
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:54
TInterface::LoadTimetableFromSessionFile
bool LoadTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
Loads timetable into memory from a session file, true if successful.
Definition: InterfaceUnit.cpp:16149
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:672
TInterface::SpeedButton125
TSpeedButton * SpeedButton125
Definition: InterfaceUnit.h:606
TInterface::SpeedButton21
TSpeedButton * SpeedButton21
Definition: InterfaceUnit.h:502
TUtilities::DateTimeStamp
AnsiString DateTimeStamp()
creates a string of the form 'dd/mm/yyyy hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:66
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:780
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4213
TInterface::SpeedButton64
TSpeedButton * SpeedButton64
Definition: InterfaceUnit.h:545
TInterface::AllEntriesTTListBoxMouseUp
void __fastcall AllEntriesTTListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:4560
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1580
TInterface::FontButton
TBitBtn * FontButton
Definition: InterfaceUnit.h:68
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:692
TInterface::NextTTEntryButtonClick
void __fastcall NextTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3272
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:197
TInterface::~TInterface
__fastcall ~TInterface()
destructor
Definition: InterfaceUnit.cpp:683
TInterface::CancelTTEntryButtonClick
void __fastcall CancelTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4244
TInterface::TTEVPtr
std::vector< AnsiString >::iterator TTEVPtr
typedef for pointers to entries in edit timetable functions
Definition: InterfaceUnit.h:862
TInterface::SaveHeaderMenu1Click
void __fastcall SaveHeaderMenu1Click(TObject *Sender)
Definition: InterfaceUnit.cpp:2829
TInterface::TTStartTimePtr
TTEVPtr TTStartTimePtr
Definition: InterfaceUnit.h:1077
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:616
TInterface::TTClockAdjPanel
TPanel * TTClockAdjPanel
Definition: InterfaceUnit.h:211
TInterface::BuildTrainDataVectorForLoadFile
bool BuildTrainDataVectorForLoadFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway, bool SessionFile)
Convert a stored timetable file (either as a stand alone file or within a session file) to a loaded t...
Definition: InterfaceUnit.cpp:16360
TInterface::CompileAllEntriesMemoAndSetPointers
void CompileAllEntriesMemoAndSetPointers(int Caller)
Used during timetable editing funtions to compile the list of entries into the left hand long entry w...
Definition: InterfaceUnit.cpp:4690
TInterface::CopiedEntryStr
AnsiString CopiedEntryStr
a timetable entry that has been copied
Definition: InterfaceUnit.h:868
TInterface::SpeedButton12
TSpeedButton * SpeedButton12
Definition: InterfaceUnit.h:493
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:16993
TInterface::SelectMenuItem
TMenuItem * SelectMenuItem
Definition: InterfaceUnit.h:407
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1578
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4198
Connection
@ Connection
Definition: TrackUnit.h:72
TInterface::TTTextButtonClick
void __fastcall TTTextButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4402
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3302
TTrainController::TrainFailedWarning
bool TrainFailedWarning
Flags to enable the relevant warning graphics to flash at the left hand side of the screen.
Definition: TrainUnit.h:702
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1555
TInterface::LengthOKButton
TBitBtn * LengthOKButton
distance/speed setting buttons - left to right & top to bottom
Definition: InterfaceUnit.h:79
TTrain::NextTrainID
static int NextTrainID
the ID value to be used for the next train that is created, static so that it doesn't need an object ...
Definition: TrainUnit.h:287
TInterface::PreviousTTEntryButtonClick
void __fastcall PreviousTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3311
TInterface::UserGraphicButton
TBitBtn * UserGraphicButton
Definition: InterfaceUnit.h:81
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:14624
TInterface::Text_Y
int Text_Y
as above for 'Y'
Definition: InterfaceUnit.h:1028
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:16295
TInterface::DeleteTTEntryButton
TButton * DeleteTTEntryButton
Definition: InterfaceUnit.h:132
DefaultTrackSpeedLimit
#define DefaultTrackSpeedLimit
Definition: TrackUnit.h:38
TInterface::ReselectUserGraphicClick
void __fastcall ReselectUserGraphicClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11936
TInterface::TTClockAdd1mButtonClick
void __fastcall TTClockAdd1mButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11551
TInterface::SubMinsButton
TButton * SubMinsButton
Definition: InterfaceUnit.h:141
TInterface::SpeedButton66
TSpeedButton * SpeedButton66
Definition: InterfaceUnit.h:547
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set TempMarker true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:6016
TInterface::ValidateTimetableButtonClick
void __fastcall ValidateTimetableButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4064
TInterface::UserGraphicMoveVPos
int UserGraphicMoveVPos
used to store the original user graphic 'H' & 'V' positions for use during moving
Definition: InterfaceUnit.h:1038
TInterface::SpeedButton98
TSpeedButton * SpeedButton98
Definition: InterfaceUnit.h:579
TActionVectorEntry::LocationName
AnsiString LocationName
Definition: TrainUnit.h:96
TInterface::LoadTimetableMenuItem
TMenuItem * LoadTimetableMenuItem
Definition: InterfaceUnit.h:390
TInterface::SpeedButton95
TSpeedButton * SpeedButton95
Definition: InterfaceUnit.h:576
TInterface::LocationNameButtonClick
void __fastcall LocationNameButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1053
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5152
TInterface::SaveMenuItem
TMenuItem * SaveMenuItem
Definition: InterfaceUnit.h:389
TInterface::GapSetting
@ GapSetting
Definition: InterfaceUnit.h:851
TTrain::TimeTimeLocArrived
bool TimeTimeLocArrived
indicates whether has arrived (true) or not when ActionVectorEntryPtr->FormatType == TimeTimeLoc
Definition: TrainUnit.h:294
TInterface::ShowHideTTButton
TBitBtn * ShowHideTTButton
Definition: InterfaceUnit.h:123
TInterface::ScreenDownButton
TBitBtn * ScreenDownButton
Definition: InterfaceUnit.h:231
TTrain::LeadEntryPos
int LeadEntryPos
Definition: TrainUnit.h:327
TTrainController::LateArrivals
int LateArrivals
Definition: TrainUnit.h:738
TInterface::DeleteOnePrefDirButton
TBitBtn * DeleteOnePrefDirButton
Definition: InterfaceUnit.h:116
TInterface::PauseEntryTTClockSpeed
float PauseEntryTTClockSpeed
rate at which the timetable clock runs on entry to the adjust routine - to restore if cancelled
Definition: InterfaceUnit.h:971
TTrainController::ReplotTrains
void ReplotTrains(int Caller, TDisplay *Disp)
plot all trains on the display
Definition: TrainUnit.cpp:8122
TInterface::MetreVariableLabel
TLabel * MetreVariableLabel
Definition: InterfaceUnit.h:102
TInterface::SigImagePanel
TPanel * SigImagePanel
new at v2.3.0 for handed signals
Definition: InterfaceUnit.h:366
TTrain::FloatingTimetableString
AnsiString FloatingTimetableString(int Caller, TActionVectorEntry *Ptr)
Used in the floating window to display the timetable.
Definition: TrainUnit.cpp:6453
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:642
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:15518
TInterface::TTClockAdd10mButtonClick
void __fastcall TTClockAdd10mButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11531
TRailGraphics::SpeedBut73GrndBlackGlyph
Graphics::TBitmap * SpeedBut73GrndBlackGlyph
Definition: GraphicUnit.h:1050
TTrain::AValue
double AValue
this is a useful shorthand value in calculating speeds and transit times in SetTrainMovementValues [=...
Definition: TrainUnit.h:371
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:6503
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:2723
TTrainController::WriteTrainsToImage
void WriteTrainsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click) to write all trains to the image file.
Definition: TrainUnit.cpp:8137
TInterface::SpeedButton30
TSpeedButton * SpeedButton30
Definition: InterfaceUnit.h:511
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:129
TInterface::TTClockSpeedLabel
TLabel * TTClockSpeedLabel
Definition: InterfaceUnit.h:308
TTrack::FourAspectBuild
@ FourAspectBuild
Definition: TrackUnit.h:752
TInterface::SpeedButton146
TSpeedButton * SpeedButton146
Definition: InterfaceUnit.h:627
TTrainController::OpTimeToActMultiMapIterator
TOpTimeToActMultiMapIterator OpTimeToActMultiMapIterator
added v2.2.0 for Op time to act display
Definition: TrainUnit.h:773
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:539
TInterface::NewEntryInPreparationFlag
bool NewEntryInPreparationFlag
true when a new timetable entry is being prepared in the timetable editor
Definition: InterfaceUnit.h:915
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:76
TInterface::OAPanelLabel
TLabel * OAPanelLabel
Definition: InterfaceUnit.h:313
TInterface::GetVersion
UnicodeString GetVersion()
determined automatically from the project options 'Version Info'
Definition: InterfaceUnit.cpp:783
TInterface::OneEntryTimetableContents
AnsiString OneEntryTimetableContents
the current text in the large right hand timetable edit window
Definition: InterfaceUnit.h:880
TInterface::SelectRect
TRect SelectRect
the rectangle in HLoc & VLoc terms set in Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1071
TTrain::ZeroPowerNoJoinedByMessage
bool ZeroPowerNoJoinedByMessage
Definition: TrainUnit.h:303
TInterface::LocationNameComboBox
TComboBox * LocationNameComboBox
the combobox that lists location names
Definition: InterfaceUnit.h:172
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:658
TInterface::ExitOperationButton
TBitBtn * ExitOperationButton
Definition: InterfaceUnit.h:202
TInterface::TTLabel6
TLabel * TTLabel6
Definition: InterfaceUnit.h:323
TInterface::SpeedButton97
TSpeedButton * SpeedButton97
Definition: InterfaceUnit.h:578
TTrainController::SaveSessionContinuationAutoSigEntries
void SaveSessionContinuationAutoSigEntries(int Caller, std::ofstream &SessionFile)
save ContinuationAutoSigEntries to a session file
Definition: TrainUnit.cpp:13957
TInterface::SignalStopImage
TImage * SignalStopImage
Definition: InterfaceUnit.h:244
TInterface::SpeedButton13
TSpeedButton * SpeedButton13
Definition: InterfaceUnit.h:494
TInterface::OutputLog9
TLabel * OutputLog9
Definition: InterfaceUnit.h:279
TInterface::SetCaption
void SetCaption(int Caller)
Sets the railway and timetable titles at the top of the screen.
Definition: InterfaceUnit.cpp:15100
TInterface::SpeedButton27
TSpeedButton * SpeedButton27
Definition: InterfaceUnit.h:508
TOnePrefDir::ExternalClearPrefDirAnd4MultiMap
void ExternalClearPrefDirAnd4MultiMap()
Empty the existing preferred direction vector & map - for use by other classes.
Definition: TrackUnit.h:1271
TInterface::SetInitialPrefDirModeEditMenu
void SetInitialPrefDirModeEditMenu()
Enables or disables the initial Edit mode submenu items in PrefDir mode.
Definition: InterfaceUnit.cpp:17785
TInterface::MainScreenMouseMove
void __fastcall MainScreenMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:6988
TInterface::DistanceContinuing
@ DistanceContinuing
Definition: InterfaceUnit.h:851
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:564
TInterface::SigsOnLeftImage2
TImage * SigsOnLeftImage2
Definition: InterfaceUnit.h:260
TInterface::ChainEdit
TEdit * ChainEdit
Definition: InterfaceUnit.h:98
TInterface::SpeedButton109
TSpeedButton * SpeedButton109
Definition: InterfaceUnit.h:590
TInterface::PasteTTEntryButtonClick
void __fastcall PasteTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3637
TInterface::SpeedButton100
TSpeedButton * SpeedButton100
Definition: InterfaceUnit.h:581
TInterface::TestFunction
void TestFunction()
Called for diagnostic purposes when keys CTRL ALT 4 pressed.
Definition: InterfaceUnit.cpp:17885
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:9817
TTrain::FirstHalfMove
bool FirstHalfMove
true when the train is on the first half of an element when it displays as fully on two elements....
Definition: TrainUnit.h:349
TInterface::MovingTrainPresentOnFlashingRoute
bool MovingTrainPresentOnFlashingRoute(int Caller)
Examines a flashing route (i.e. one being set) and returns true if a moving train is detected on it a...
Definition: InterfaceUnit.cpp:12375
TInterface::Level2TrackMode
enum TInterface::TLevel2TrackMode Level2TrackMode
TInterface::SpeedButton65
TSpeedButton * SpeedButton65
Definition: InterfaceUnit.h:546
TTrainController::LatePasses
int LatePasses
Definition: TrainUnit.h:740
TInterface::SaveRailwayBaseModeButton
TBitBtn * SaveRailwayBaseModeButton
Save button at the top left hand corner of the screen when no mode is selected.
Definition: InterfaceUnit.h:58
TInterface::SelectBiDirPrefDirsMenuItem
TMenuItem * SelectBiDirPrefDirsMenuItem
Definition: InterfaceUnit.h:417
TInterface::UserGraphicReselectPanel
TPanel * UserGraphicReselectPanel
Definition: InterfaceUnit.h:460
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:97
TInterface::RotLeftMenuItem
TMenuItem * RotLeftMenuItem
Definition: InterfaceUnit.h:453
TInterface::TTClockxQuarterButtonClick
void __fastcall TTClockxQuarterButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11455
TTrainController::SSHigh
bool SSHigh
Definition: TrainUnit.h:713
TInterface::TextOrUserGraphicGridVal
int TextOrUserGraphicGridVal
stores the text alignment grid value, cycles forwards through 1, 2, 4, 8 & 16 each time the text grid...
Definition: InterfaceUnit.h:1030
TimeLoc
@ TimeLoc
Definition: TrainUnit.h:62
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:209
TInterface::FileMenu
TMenuItem * FileMenu
Definition: InterfaceUnit.h:386
TTrainController::AvHoursIntValue
int AvHoursIntValue
Input in MTBFEditBox in timetable hours, min value is 1 and max is 10,000. Here because performance f...
Definition: TrainUnit.h:758
TTrainController::CrashedTrains
int CrashedTrains
Definition: TrainUnit.h:733
TInterface::OutputLog3MouseDown
void __fastcall OutputLog3MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10689
TInterface::SpeedConversionPanel
TPanel * SpeedConversionPanel
Definition: InterfaceUnit.h:105
TTrain::LogAction
void LogAction(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionType ActionType, AnsiString LocationName, TDateTime TimetableNonRepeatTime, bool Warning)
Send a message to the performance log and performance file, and if the message is flagged as a warnin...
Definition: TrainUnit.cpp:4786
TInterface::SpeedButton22
TSpeedButton * SpeedButton22
Definition: InterfaceUnit.h:503
TTextHandler::SaveText
void SaveText(int Caller, std::ofstream &VecFile)
save the railway's text to VecFile
Definition: TextUnit.cpp:313
TTrain::StoppedAtSignal
bool StoppedAtSignal
Definition: TrainUnit.h:427
TInterface::SpeedButton130
TSpeedButton * SpeedButton130
Definition: InterfaceUnit.h:611
TTrack::GetGapHLoc
int GetGapHLoc()
Definition: TrackUnit.h:755
TInterface::ResetDefaultLengthButton
TBitBtn * ResetDefaultLengthButton
Definition: InterfaceUnit.h:77
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise points: 0=set to ...
Definition: TrackUnit.h:138
TInterface::PauseEntryRestartTime
double PauseEntryRestartTime
time value of the timetable restart time (as a double) on entry to pause mode
Definition: InterfaceUnit.h:968
TInterface::SelectBiDirPrefDirsMenuItemClick
void __fastcall SelectBiDirPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9259
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4093
TInterface::SigsOnRightImage2
TImage * SigsOnRightImage2
Definition: InterfaceUnit.h:262
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:698
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4090
TInterface::AddTrack
@ AddTrack
Definition: InterfaceUnit.h:851
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1669
TInterface::ClearAllMenuItem
TMenuItem * ClearAllMenuItem
Definition: InterfaceUnit.h:393
TTrainController::THCandTrainPosParam
std::pair< AnsiString, int > THCandTrainPosParam
Definition: TrainUnit.h:688
TInterface::SaveImageNoGridMenuItem
TMenuItem * SaveImageNoGridMenuItem
Definition: InterfaceUnit.h:428
TInterface::SelectMenuItemClick
void __fastcall SelectMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8505
TRailGraphics::SpeedBut74NormBlackGlyph
Graphics::TBitmap * SpeedBut74NormBlackGlyph
Definition: GraphicUnit.h:1043
TInterface::StartY
int StartY
the mouse position in terms of pixels when an item of text is being selected for moving
Definition: InterfaceUnit.h:1022
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:63
TInterface::UpdateOperatorActionPanel
void UpdateOperatorActionPanel(int Caller)
Called every 5 secs to update the panel (if visible)
Definition: InterfaceUnit.cpp:17983
TInterface::TextBoxKeyPress
void __fastcall TextBoxKeyPress(TObject *Sender, char &Key)
Definition: InterfaceUnit.cpp:1013
TInterface::SaveTimetableToSessionFile
bool SaveTimetableToSessionFile(int Caller, std::ofstream &SessionFile, AnsiString SessionFileStr)
Called during a session save to save the current timetable in the session file, true if successful.
Definition: InterfaceUnit.cpp:16032
TInterface::SpeedButton71
TSpeedButton * SpeedButton71
Definition: InterfaceUnit.h:552
TInterface::DeleteAllPrefDirButtonClick
void __fastcall DeleteAllPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1855
Platform
@ Platform
Definition: TrackUnit.h:63
TInterface::RlyFile
bool RlyFile
indicates that a loaded railway file is ready for operation, i.e. is a valid .rly file
Definition: InterfaceUnit.h:923
TInterface::RestartSessionOperMode
@ RestartSessionOperMode
Definition: InterfaceUnit.h:821
TInterface::PreferredRouteFlag
bool PreferredRouteFlag
used to select either ConvertAndAddPreferredRouteSearchVector or ConvertAndAddNonPreferredRouteSearch...
Definition: InterfaceUnit.h:919
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:663
TInterface::TextMoveHPos
int TextMoveHPos
Definition: InterfaceUnit.h:1034
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4115
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:633
TInterface::PowerTopLabel
TLabel * PowerTopLabel
Definition: InterfaceUnit.h:187
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:674
TInterface::SpeedButton129
TSpeedButton * SpeedButton129
Definition: InterfaceUnit.h:610
TInterface::RepairFailedTrainMenuItem
TMenuItem * RepairFailedTrainMenuItem
Definition: InterfaceUnit.h:455
TUtilities::CheckAndCompareFileString
bool CheckAndCompareFileString(std::ifstream &InFile, AnsiString InString)
checks that the value is a string ('0' or CR accepted as delimiters) and is the same as InString,...
Definition: Utilities.cpp:412
TInterface::CutTTEntryButton
TButton * CutTTEntryButton
Definition: InterfaceUnit.h:130
TInterface::MileEdit
TEdit * MileEdit
Definition: InterfaceUnit.h:97
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1177
TInterface::TTClockx8ButtonClick
void __fastcall TTClockx8ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11379
TInterface::SetLevel2OperMode
void SetLevel2OperMode(int Caller)
Sets the Level2OperMode user mode, using the Level2OperMode variable to determine the mode.
Definition: InterfaceUnit.cpp:13582
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:8035
TInterface::RestoreTTButton
TButton * RestoreTTButton
Definition: InterfaceUnit.h:146
TTrain::TimetableFinished
bool TimetableFinished
set when there are no more timetable actions
Definition: TrainUnit.h:367
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1483
TInterface::EraseLocationNameText
bool EraseLocationNameText(int Caller, AnsiString Name, int &HPos, int &VPos)
Erase a location name (providing it exists in LocationNameMultiMap) from TextVector,...
Definition: InterfaceUnit.cpp:17827
TInterface::PrefDirKey
TImage * PrefDirKey
information panel displayed when setting preferred directions
Definition: InterfaceUnit.h:249
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:54
TActionVectorEntry::Command
AnsiString Command
Definition: TrainUnit.h:96
TInterface::SpeedButton138
TSpeedButton * SpeedButton138
Definition: InterfaceUnit.h:619
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:700
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:146
TInterface::DeleteAllPrefDirButton
TBitBtn * DeleteAllPrefDirButton
Definition: InterfaceUnit.h:117
TInterface::SpeedButton117
TSpeedButton * SpeedButton117
Definition: InterfaceUnit.h:598
TTrain::SignallerStoppingFlag
bool SignallerStoppingFlag
set when the signaller stop command has been given
Definition: TrainUnit.h:361
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:140
TInterface::SpeedButton39
TSpeedButton * SpeedButton39
Definition: InterfaceUnit.h:520
TTrack::BuildBasicElementFromSpeedTag
TTrackElement BuildBasicElementFromSpeedTag(int Caller, int SpeedTag)
Return a basic track element from the SpeedTag new at v2.2.0 - needed because Interface doesn't have ...
Definition: TrackUnit.h:807
TInterface::TTStartTimeBox
TEdit * TTStartTimeBox
edit box that displays the timetable start time
Definition: InterfaceUnit.h:170
TInterface::AddPrefDirButtonClick
void __fastcall AddPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1828
TInterface::ShiftKey
bool ShiftKey
true when the SHIFT key is pressed (used for large movements of the screen)
Definition: InterfaceUnit.h:939
TTrainController::SigSLow
bool SigSLow
Message flags in TT checks to stop being given twice.
Definition: TrainUnit.h:713
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:526
TInterface::AddMinsButtonClick
void __fastcall AddMinsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3370
RemoveTrain
@ RemoveTrain
Definition: TrainUnit.h:50
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3202
TInterface::FontButtonClick
void __fastcall FontButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1758
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:99
TInterface::SigAspectButtonClick
void __fastcall SigAspectButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1719
TInterface::SetLevel2TrackMode
void SetLevel2TrackMode(int Caller)
Sets the Level2TrackMode user mode, using the Level2TrackMode variable to determine the mode.
Definition: InterfaceUnit.cpp:12967
TTrainController::SetWarningFlags
void SetWarningFlags(int Caller)
This sets all the warning flags (CrashWarning, DerailWarning etc) to their required states after a se...
Definition: TrainUnit.cpp:15049
TInterface::None
@ None
Definition: InterfaceUnit.h:856
TInterface::SpeedButton87
TSpeedButton * SpeedButton87
Definition: InterfaceUnit.h:568
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:112
TInterface::FormClose
void __fastcall FormClose(TObject *Sender, TCloseAction &Action)
Definition: InterfaceUnit.cpp:10124
TInterface::SigAspectButton
TBitBtn * SigAspectButton
Definition: InterfaceUnit.h:74
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:9360
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:646
TInterface::SpeedButton127
TSpeedButton * SpeedButton127
Definition: InterfaceUnit.h:608
TTrainController::TotEarlyPassMins
float TotEarlyPassMins
Definition: TrainUnit.h:727
TTrainController::OpTimeToActMultiMap
TOpTimeToActMultiMap OpTimeToActMultiMap
added v2.2.0 for Op time to act display
Definition: TrainUnit.h:771
TInterface::SelectBitmapMouseLocY
int SelectBitmapMouseLocY
see above
Definition: InterfaceUnit.h:1012
TTrain::BrakeRate
double BrakeRate
the current train brake rate
Definition: TrainUnit.h:389
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:146
TTrack::GapFlashFlag
bool GapFlashFlag
true when a pair of connected gaps is flashing
Definition: TrackUnit.h:644
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:535
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:82
TInterface::StartX
int StartX
Definition: InterfaceUnit.h:1022
TrainUnit.h
TTrack::LevelCrossingBarrierUpFlashDuration
float LevelCrossingBarrierUpFlashDuration
duration of the flash period when level crossing closing to trains
Definition: TrackUnit.h:661
TTrainController::IncorrectExits
int IncorrectExits
Definition: TrainUnit.h:737
TUtilities::SetLocaleResultOK
bool SetLocaleResultOK
flag to indicate whether the call to setlocale() in InterfaceUnit.cpp succeeded or not
Definition: Utilities.h:41
TInterface::SelectLengthsFlag
bool SelectLengthsFlag
true when 'Set lengths &/or speeds' selected in the 'Edit' menu
Definition: InterfaceUnit.h:933
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:86
TRailGraphics::LockedRouteCancelPtr
Graphics::TBitmap * LockedRouteCancelPtr[10]
for locked route cancel graphic, 1 for each of 8 links, 0 & 5 included as for direction
Definition: GraphicUnit.h:1029
TInterface::TrackOKButton
TBitBtn * TrackOKButton
Definition: InterfaceUnit.h:64
TInterface::SpeedButton23
TSpeedButton * SpeedButton23
Definition: InterfaceUnit.h:504
TInterface::RailwayTitle
AnsiString RailwayTitle
Definition: InterfaceUnit.h:884
TDisplay::Rectangle
void Rectangle(int Caller, int HPos, int VPos, TColor Col, int Size, int Width)
Plot a rectangle at the defined position with colour Col & size defined by Size.
Definition: DisplayUnit.cpp:153
TInterface::SpeedButton20
TSpeedButton * SpeedButton20
Definition: InterfaceUnit.h:501
TInterface::CheckInterface
bool CheckInterface(int Caller, std::ifstream &SessionFile)
Check the interface part of a session file & return false for error, called during SessionFileIntegri...
Definition: InterfaceUnit.cpp:15798
TInterface::PreStart
@ PreStart
Definition: InterfaceUnit.h:843
AboutForm
TAboutForm * AboutForm
Definition: AboutUnit.cpp:47
TInterface::SpeedButton137
TSpeedButton * SpeedButton137
Definition: InterfaceUnit.h:618
TInterface::ExitTTModeButton
TBitBtn * ExitTTModeButton
Definition: InterfaceUnit.h:124
TTrain::SetTrainMovementValues
void SetTrainMovementValues(int Caller, int TrackVectorPosition, int EntryPos)
Calculates train speeds and times for the element that the train is about to enter....
Definition: TrainUnit.cpp:3293
TActionVectorEntry::Warning
bool Warning
if set triggers an alert in the warning panel when the action is reached
Definition: TrainUnit.h:100
TInterface::OverallSpeedLimit
int OverallSpeedLimit
and the overall speed limit, if the speed limits vary across the selection the value is set to -1
Definition: InterfaceUnit.h:1000
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:9751
TInterface::SpeedButton78
TSpeedButton * SpeedButton78
Definition: InterfaceUnit.h:559
TRailGraphics::SpeedBut75GrndBlackGlyph
Graphics::TBitmap * SpeedBut75GrndBlackGlyph
Definition: GraphicUnit.h:1052
TTrainDataEntry::ServiceReference
AnsiString ServiceReference
Definition: TrainUnit.h:179
TInterface::PowerEditBox
TEdit * PowerEditBox
Definition: InterfaceUnit.h:186
TInterface::TimetableHandler
void TimetableHandler()
Called during timetable editing whenever a change is made to the timetable, sets all the timetable bu...
Definition: InterfaceUnit.cpp:4977
TTrain::SignallerChangeTrainDirection
void SignallerChangeTrainDirection(int Caller)
Unplots & replots train, which checks for facing signal and sets StoppedAtSignal if req'd.
Definition: TrainUnit.cpp:6320
TInterface::CancelSelectionMenuItem
TMenuItem * CancelSelectionMenuItem
Definition: InterfaceUnit.h:418
TTrain::ZeroPowerNoRearSplitMessage
bool ZeroPowerNoRearSplitMessage
Definition: TrainUnit.h:301
TInterface::SpeedButton68
TSpeedButton * SpeedButton68
Definition: InterfaceUnit.h:549
TInterface::LoadSession
void LoadSession(int Caller)
Load a session file.
Definition: InterfaceUnit.cpp:15443
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:15558
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:16565
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:88
TInterface::SigRouteStartMarker
TGraphicElement * SigRouteStartMarker
Definition: InterfaceUnit.h:1054
TInterface::SetGapsButtonClick
void __fastcall SetGapsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:954
TInterface::SignallerControlStopMenuItemClick
void __fastcall SignallerControlStopMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9836
TInterface::PrefDirSelecting
@ PrefDirSelecting
Definition: InterfaceUnit.h:847
TInterface::TimetableDialog
TOpenDialog * TimetableDialog
Definition: InterfaceUnit.h:467
TInterface::MissedTicks
unsigned int MissedTicks
missed clock ticks
Definition: InterfaceUnit.h:988
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:9389
TInterface::MoveTTEntryUpButton
TButton * MoveTTEntryUpButton
Definition: InterfaceUnit.h:133
TInterface::RotateMenuItem
TMenuItem * RotateMenuItem
Definition: InterfaceUnit.h:413
TInterface::SpeedButton33
TSpeedButton * SpeedButton33
Definition: InterfaceUnit.h:514
TInterface::TTClockxSixteenthButtonClick
void __fastcall TTClockxSixteenthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11492
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:587
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:499
TUtilities::Clock2Stopped
bool Clock2Stopped
when true the main loop - Interface->ClockTimer2 - is stopped
Definition: Utilities.h:37
TTrainController::MRSHigh
bool MRSHigh
Definition: TrainUnit.h:713
TInterface::FlipMenuItem
TMenuItem * FlipMenuItem
Definition: InterfaceUnit.h:411
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:5569
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:155
TInterface::SessionFileIntegrityCheck
bool SessionFileIntegrityCheck(int Caller, AnsiString FileName)
Checks session file integrity prior to loading, true for success.
Definition: InterfaceUnit.cpp:16528
TInterface::TrainFailedImage
TImage * TrainFailedImage
Definition: InterfaceUnit.h:457
TTrain::NotInService
bool NotInService
Definition: TrainUnit.h:428
TInterface::RotLeftMenuItemClick
void __fastcall RotLeftMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9007
TInterface::SpeedButton14
TSpeedButton * SpeedButton14
Definition: InterfaceUnit.h:495
TInterface::ExitTrackButton
TBitBtn * ExitTrackButton
Definition: InterfaceUnit.h:75
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:640
TInterface::SpeedButton110
TSpeedButton * SpeedButton110
Definition: InterfaceUnit.h:591
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:52
TInterface::OutputLog10
TLabel * OutputLog10
Definition: InterfaceUnit.h:280
TInterface::SESSION_DIR_NAME
static const UnicodeString SESSION_DIR_NAME
Definition: InterfaceUnit.h:835
TInterface::FileChangedFlag
bool FileChangedFlag
true when a loaded railway file has changed (used to warn user if opts to exit without saving)
Definition: InterfaceUnit.h:909
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:140
TInterface::CutTTEntryButtonClick
void __fastcall CutTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3563
TInterface::AutoSigsButtonClick
void __fastcall AutoSigsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1977
TRailGraphics::SpeedBut69GrndBlackGlyph
Graphics::TBitmap * SpeedBut69GrndBlackGlyph
Definition: GraphicUnit.h:1046
Signaller
@ Signaller
Definition: TrainUnit.h:56
TRailGraphics::bmRedRect
Graphics::TBitmap * bmRedRect
Definition: GraphicUnit.h:526
TInterface::SaveOperatingImageMenuItemClick
void __fastcall SaveOperatingImageMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2701
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:49
TInterface::ConstructRoute
TOneRoute * ConstructRoute
the route under construction
Definition: InterfaceUnit.h:1068
TInterface::SpeedButton118
TSpeedButton * SpeedButton118
Definition: InterfaceUnit.h:599
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:8716
Bridge
@ Bridge
Definition: TrackUnit.h:63
TInterface::DirOpenError
bool DirOpenError
true when one of the program subfolders doesn't already exist and can't be created
Definition: InterfaceUnit.h:903
TInterface::CutMenuItemClick
void __fastcall CutMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8588
TInterface::SpeedButton38
TSpeedButton * SpeedButton38
Definition: InterfaceUnit.h:519
TInterface::ResetCurrentSpeedButton
void ResetCurrentSpeedButton(int Caller)
Resets the CurrentSpeedButton variable to zero and the 'Down' property to false.
Definition: InterfaceUnit.cpp:12364
TInterface::SpeedButton102
TSpeedButton * SpeedButton102
Definition: InterfaceUnit.h:583
TTrain::TimetableMaxRunningSpeed
double TimetableMaxRunningSpeed
the maximum train running speed when in timetable mode (see int SignallerMaxSpeed for signaller contr...
Definition: TrainUnit.h:381
TInterface::SpeedButton99
TSpeedButton * SpeedButton99
Definition: InterfaceUnit.h:580
clB0G0R0
#define clB0G0R0
Definition: GraphicUnit.h:36
Buffers
@ Buffers
Definition: TrackUnit.h:63
TInterface::SelectGraphic
@ SelectGraphic
Definition: InterfaceUnit.h:851
TTextHandler::TextMove
void TextMove(int Caller, int HPosInput, int VPosInput, int &TextItem, int &TextMoveHPos, int &TextMoveVPos, bool &TextFoundFlag)
Definition: TextUnit.cpp:196
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:49
clFrontCodeTimetable
#define clFrontCodeTimetable
Definition: GraphicUnit.h:296
TTrack::UserGraphicPresentAtHV
bool UserGraphicPresentAtHV(int Caller, int HPos, int VPos, int &UGIVectorPos)
checks if a user graphic present
Definition: TrackUnit.h:733
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:9775
TInterface::ExitTTModeButtonClick
void __fastcall ExitTTModeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4435
TInterface::MirrorMenuItemClick
void __fastcall MirrorMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8682
TInterface::SpeedButton11
TSpeedButton * SpeedButton11
Definition: InterfaceUnit.h:492
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:13886
TInterface::SigPrefButton
TBitBtn * SigPrefButton
Definition: InterfaceUnit.h:195
TInterface::RouteNotStarted
@ RouteNotStarted
Definition: InterfaceUnit.h:856
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4028
TInterface::SaveImageAndGridMenuItem
TMenuItem * SaveImageAndGridMenuItem
Definition: InterfaceUnit.h:429
TInterface::SpeedButton48
TSpeedButton * SpeedButton48
Definition: InterfaceUnit.h:529
TInterface::WhiteBgndMenuItemClick
void __fastcall WhiteBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10850